# Express

Add ProductLense to an Express app in the shared layout template, then identify signed-in users from the session safely.

In an Express app the browser script goes into the layout that renders the `<head>` of every page. The examples use EJS; the same two tags work in Pug, Handlebars or HTML you send with `res.send`.

## Add the script

Replace `SITE_ID` with the id from Settings → Sites in the ProductLense dashboard.

```html title="views/partials/head.ejs" {3-4}
<meta charset="utf-8" />
<title><%= title %></title>
<script>window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
<script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
```

Include the partial in the `<head>` of your layout with `<%- include('partials/head') %>`. If you set a Content-Security-Policy with Helmet, allow `https://api.productlense.app` in `script-src` and `connect-src`; see [Content Security Policy](/docs/install/script-tag#content-security-policy).

## Identify users

Pass the signed-in user's id to the template and print it as JSON, so quotes and `<` in the value cannot break out of the script:

```js title="app.js" {3}
app.use((req, res, next) => {
  // Escape "<" so the value can never close the script tag.
  res.locals.productLenseUserId = JSON.stringify(req.session?.userId ?? null).replace(/</g, '\\u003c');
  next();
});
```

```html title="views/partials/head.ejs" {2}
<script>
  var uid = <%- productLenseUserId %>;
  if (uid) window.productlense('identify', String(uid));
</script>
```

Place this after the queue stub. Use the same id you store on the customer in your billing provider; see [how payments are attributed](/docs/revenue/attribution).

## Events from your server

Actions that happen only on the server, such as a webhook that converts a trial, can be sent to the Events API with an API key. API keys are on the Scale plan; see [server-side events](/docs/install/server-side-events).

## Verify your installation

1. Deploy, then open your site in a normal browser window.
2. Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds.
3. In the browser's developer tools, the Network tab shows a `POST` to `https://api.productlense.app/api/e` with status `204`.

An app running on `localhost` sends nothing unless you add `data-dev="true"` to the tag. Ad blockers in your own browser may block the request. If the visit does not appear, follow [Verify your installation](/docs/install/verify).
