# Express

URL: https://pieowl.com/docs/sdks/express





<Callout>
  Looking for a step-by-step tutorial? Read the [Express analytics guide](/guides/express-analytics).
</Callout>

Good to know [#good-to-know]

An Express app needs up to three pieces. Use the ones you need:

* **Pages and visitors**: the [HTML script](/docs/sdks/script) in the pages Express serves.
* **AI crawlers and bots**: `@pieowl/bots`, which reports the bots the script can't see.
* **Server-side events** (sign-ups, payments): `@pieowl/sdk`.

Track pages [#track-pages]

Add the script to your HTML template (EJS, Pug, Handlebars or static files) and replace `YOUR_CLIENT_ID` with your client ID.

```html title="views/layout.html"
<script src="https://pieowl.com/pieowl.js" data-client-id="YOUR_CLIENT_ID" defer></script>
```

For events, identifying users and all options, see the [Script Tag](/docs/sdks/script) docs.

Track AI crawlers and bots [#track-ai-crawlers-and-bots]

```bash
npm install @pieowl/bots
```

```ts
import { trackBots } from '@pieowl/bots/express';

app.use(trackBots({
  clientId: process.env.PIEOWL_CLIENT_ID,
  clientSecret: process.env.PIEOWL_CLIENT_SECRET,
}));
```

Requests from AI and search bots are reported after the response is sent, with the status code. Visitors cause no extra work. Behind a proxy or load balancer, set Express's [`trust proxy`](https://expressjs.com/en/guide/behind-proxies.html) so `req.ip` is the bot's IP. Read more in [AI crawlers and bots](/docs/ai-bots).

Avoid ad blockers [#avoid-ad-blockers]

Serve the script and send events through your own domain:

```ts
import { createRouteHandler } from '@pieowl/bots/express';

app.use('/api/pieowl', createRouteHandler());
```

Then switch to the [`init` form](/docs/sdks/script#options-in-code), set `apiUrl: '/api/pieowl'` in `init`, and load the script from `/api/pieowl/pieowl.js`. See [Avoid ad blockers](/docs/adblockers).

Server-side events [#server-side-events]

Use the [JavaScript SDK](/docs/sdks/javascript) with your client secret. Keep the secret on the server.

```bash
npm install @pieowl/sdk
```

```ts title="pieowl.ts"
import { Pieowl } from '@pieowl/sdk';

export const pieowl = new Pieowl({
  clientId: process.env.PIEOWL_CLIENT_ID,
  clientSecret: process.env.PIEOWL_CLIENT_SECRET,
});
```

```ts
import { pieowl } from './pieowl';

app.post('/sign-up', async (req, res) => {
  const user = await createUser(req.body);
  // Pass profileId on each call: one instance serves every visitor.
  pieowl.track('sign_up', { profileId: user.id, plan: req.body.plan });
  res.json({ ok: true });
});
```

Server events get their location from the request IP, which is your server's. To use the visitor's location, create an instance for the request and forward the IP and user agent:

```ts
import { Pieowl } from '@pieowl/sdk';

function pieowlFor(req) {
  const pieowl = new Pieowl({
    clientId: process.env.PIEOWL_CLIENT_ID,
    clientSecret: process.env.PIEOWL_CLIENT_SECRET,
  });
  if (req.ip) pieowl.api.addHeader('pieowl-client-ip', req.ip);
  pieowl.api.addHeader('user-agent', req.get('user-agent') ?? '');
  return pieowl;
}
```

Working with groups [#working-with-groups]

Groups let you track analytics at the account or company level. See the [Groups guide](/docs/get-started/groups) for the full walkthrough.

<PersonalDataWarning />

```ts
app.post('/login', async (req, res) => {
  const user = await loginUser(req.body);
  const pieowl = pieowlFor(req);

  pieowl.identify({ profileId: user.id, email: user.email });
  pieowl.upsertGroup({
    id: user.organizationId,
    type: 'company',
    name: user.organizationName,
    properties: { plan: user.plan },
  });
  pieowl.setGroup(user.organizationId);

  res.json({ ok: true });
});
```

For every method, see the [JavaScript SDK](/docs/sdks/javascript#usage).
