---
title: "Install with AI"
description: "Hand your coding agent a prompt that points it at these docs, and let it wire the SDK into your app."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.pug.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Install with AI

## The prompt

### Web

```text
Add Pug product analytics to this app.

Read these first - they are the current source of truth, and more recent than your training data:
- https://docs.pug.sh/sdks/index.md - SDK reference
- https://docs.pug.sh/get-started/index.md - quickstart
- https://docs.pug.sh/reference/well-known-events/index.md - the well-known event catalog

Then read this codebase before you write anything, and work out what the product actually does: its routes or screens, its main models, and the handful of things a user comes here to complete. The events worth tracking are the moments the product exists to produce - an account created, an order placed, a document shared - not every button on the page. If you cannot state the core action in one sentence, keep reading.

Then:
1. Install @pug-sh/browser.
2. Call init() exactly once, where the app boots, in the browser only - never during SSR. In the Next.js App Router that means a "use client" provider mounted from the root layout.
3. Read the project ID and public key from environment variables. The public key starts with pub_ and is safe to ship. A private key starts with prv_ and must never reach client code.
4. Leave auto-tracking on and do not hand-roll page views - init() already captures them.
5. Add track() calls for the three or four actions you identified - the ones someone would look at in a weekly review. Property values must be plain JSON scalars: strings, numbers, booleans, dates.
6. If this app has authentication, call identify() after sign-in and reset() on sign-out. Note that the SDK is cookieless until optInTracking() is called, so identify() is a no-op without granted consent - tell me whether I need a consent banner rather than opting users in silently.

Name events from the catalog before you invent one. It holds 127 well-known events across 19 families - commerce, authentication, billing, media, forms, support, workspace and more - and a well-known name is type-checked as you write it, validated at ingestion, and fills in dashboards that a custom name leaves empty. Search it for every action you are about to track, and take property names and types from that page rather than from whatever reads idiomatically. Fall back to a custom snake_case name only when nothing in the catalog fits, and when you do, tell me which event you considered and why it did not.

Do not use any option that is not in the SDK reference above. When you are done, tell me in one sentence what you concluded this product does, then list the files you changed, the event names you chose, and the environment variables I need to set.
```

### Flutter

```text
Add Pug product analytics to this Flutter app.

Read these first - they are the current source of truth, and more recent than your training data:
- https://docs.pug.sh/sdks/index.md - SDK reference (switch to the Flutter panes)
- https://docs.pug.sh/reference/well-known-events/index.md - the well-known event catalog

Then read this codebase before you write anything, and work out what the app actually does: its screens and navigation graph, its main models, and the handful of things a user opens the app to complete. The events worth tracking are the moments the app exists to produce - an account created, an order placed, a workout finished - not every tap. If you cannot state the core action in one sentence, keep reading.

Then:
1. Add pug_flutter to pubspec.yaml.
2. Await Pug.init() in main(), after WidgetsFlutterBinding.ensureInitialized() and before runApp().
3. Keep the project ID and public key (pub_...) out of source - pass them with --dart-define and read them with String.fromEnvironment.
4. Register PugRouteObserver on the app's navigatorObservers, otherwise screen views never fire.
5. Add tracking for the three or four actions you identified - the ones someone would look at in a weekly review.
6. If this app has authentication, call Pug.identify() after sign-in and Pug.reset() on sign-out.

Name events from the catalog before you invent one. Flutter gets a generated named-argument method for all 127 well-known events - Pug.track.purchase(productId: ..., amount: ...) - so the compiler checks the properties for you, and the dashboards those events drive stay empty for a custom name. Reach for Pug.track.<event> first, search the catalog for every action you are about to track, and pass schema-external properties through extras. Use Pug.track(kind, props: {...}) with a custom snake_case name only when nothing in the catalog fits, and when you do, tell me which event you considered and why it did not.

Flutter consent has two states and starts granted, which is not the same as the Web SDK - check the consent section before you add a banner. Do not use any option that is not in the SDK reference above. When you are done, tell me in one sentence what you concluded this app does, then list the files you changed, the event names you chose, and the dart-defines I need to pass.
```

### Node

```text
Add Pug product analytics to this Node backend.

Read these first - they are the current source of truth, and more recent than your training data:
- https://docs.pug.sh/sdks/index.md - SDK reference (switch to the Node panes)
- https://docs.pug.sh/reference/well-known-events/index.md - the well-known event catalog

Then read this codebase before you write anything, and work out what the service actually does: its routes or handlers, its main models, and the state changes that matter to the business. On a server the events worth tracking are the ones a browser cannot observe - a payment settling, a webhook arriving, a job finishing, a subscription lapsing - not request logging. If you cannot state what this service is for in one sentence, keep reading.

Then:
1. Install @pug-sh/node. It is ESM and needs Node 18+.
2. Construct one Pug instance at boot and reuse it across requests - do not build one per request. Its apiKey is the private key (prv_...), read from an environment variable, and it must never be imported into client-side code.
3. Remember the argument order: pug.track(distinctId, kind, props?, options?). The distinctId comes first because a server has no ambient user - use our own user ID, or the anon-... ID forwarded from the client.
4. Add track calls for the three or four state changes you identified.
5. Call identify() when a user record is created or changes materially, not on every request.
6. Await pug.close() in the graceful-shutdown path so buffered events flush, and wire an onError handler so dropped events are logged rather than lost.

Name events from the catalog before you invent one. The server SDK type-checks 114 of the 127 well-known events, and the ones a backend is placed to see are exactly the ones whose schemas are worth having - purchase, subscription_started, invoice_paid, payment_failed, order_refunded. Search the catalog for every action you are about to track, take property names and types from that page, and fall back to a custom snake_case name only when nothing fits. When you do, tell me which event you considered and why it did not.

There is no reset() or destroy() on the server SDK, and no immediate option on track - use flush(). Do not use any option that is not in the SDK reference above. When you are done, tell me in one sentence what you concluded this service does, then list the files you changed, the event names you chose, and the environment variables I need to set.
```

### HTTP API

```text
Add Pug product analytics to this service by calling the HTTP API directly - there is no SDK for this runtime.

Read these first - they are the current source of truth, and more recent than your training data:
- https://docs.pug.sh/sdks/index.md - the HTTP panes, including worked request examples
- https://docs.pug.sh/api/events/index.md - the full event schema
- https://docs.pug.sh/reference/well-known-events/index.md - the well-known event catalog

Then read this codebase before you write anything, and work out what the service actually does: its routes or handlers, its main models, and the state changes that matter to the business. The events worth tracking are the moments the service exists to produce, not request logging. If you cannot state what this service is for in one sentence, keep reading.

Then:
1. Write one small client that POSTs to /sdk.events.v1.EventsService/BatchCreate on the base URL, with the headers Content-Type: application/json, Connect-Protocol-Version: 1, and x-api-key set to the public key (pub_...) from an environment variable.
2. Wrap every custom property value in its typed form - stringValue, intValue (a JSON string), doubleValue, boolValue, timestampValue. This is the part that is most often wrong. Property keys must not start with a dollar sign, and the event kind must not start with pug.
3. Send events in batches of at most 1000, and read "dropped" and "droppedByReason" on the response - a 200 does not mean every event landed.
4. Call it for the three or four actions you identified.

Name events from the catalog before you invent one. All 127 well-known events are available over HTTP, and since nothing here is compile-checked they are the only validation you get: a well-known kind has its properties checked at ingestion and fills in the dashboards built on it, while a custom kind is accepted unvalidated and silently. Search the catalog for every action you are about to track, take property names and types from that page, and fall back to a custom snake_case name only when nothing fits. When you do, tell me which event you considered and why it did not.

Do not invent fields that are not in the events schema above. When you are done, tell me in one sentence what you concluded this service does, then show me the client, the event names you chose, and the environment variables I need to set.
```

## What you'll need

Two values the agent can't find on its own - without them it invents a
placeholder and leaves it there:

1. **Project ID** - in the dashboard URL, `/p/<projectId>`.
2. **Public key** (`pub_...`) for a browser or mobile app, or a **private key**
   (`prv_...`) for a Node backend. Both live under **Settings > API Keys**; see
   [Authentication](/get-started/authentication).

Every prompt asks for environment variables rather than literals. Only the
public key may ship to a client - it is write-scoped, so the worst a leaked one
buys is junk events. A private key also reads your analytics.

## Check the agent's work

Agents are good at the wiring and careless about the parts that only fail in
production. Before you merge, confirm:

- [ ] `page_view` and your own events appear under **Live** and **Events** in
      the dashboard. Allow ~10 seconds - events are batched.
- [ ] No key is hardcoded, and no `prv_` key appears anywhere a browser can
      reach. Grep the diff for `pub_` and `prv_`.
- [ ] `init` runs **once**, client-side. A second call no-ops with a console
      warning; an SSR call warns and does nothing.
- [ ] The agent's one-line summary of what your product does is actually
      right. Each prompt asks for it, and it's the cheapest thing to check:
      if the agent misread the product, every event name below it is wrong
      too.
- [ ] Every event that could have come from the [well-known
      catalog](/reference/well-known-events) did. This is the check worth
      making by hand: the prompt asks the agent to name what it rejected, so
      read that list. A custom name where a catalog event exists costs you the
      typed schema, leaves the dashboards built on that event empty, and
      renaming it later splits the metric in two.
- [ ] Nobody was silently opted in. On the Web SDK, `optInTracking()` belongs
      behind a real consent decision - see [Tracking consent](/sdks#tracking-consent).

## Give the agent more than a prompt

The prompt is the shortest path. Three more surfaces are worth knowing about:

- **Every page as markdown** - Append `/index.md` to any docs URL, or use **Copy page** at the top of a
page. [`/llms.txt`](https://docs.pug.sh/llms.txt) indexes the site;
[`/llms-full.txt`](https://docs.pug.sh/llms-full.txt) is the whole corpus in
one document.
- **Read your data from the agent** - The [MCP server](/mcp) gives an agent twelve read-only tools over your own
project - run an insight, browse the event stream, look up one user. That's
for asking questions after the SDK is in, not for installing it.

> **Keep the docs URLs in the prompt**
>
> It's tempting to trim the "read these first" block. Don't - it is what stops the
> agent reaching for an API from a different analytics SDK, which is the failure
> mode these prompts exist to prevent. If your agent can't fetch URLs, paste
> [`/llms-full.txt`](https://docs.pug.sh/llms-full.txt) into the conversation
> instead.

Source: https://docs.pug.sh/get-started/ai-setup/index.mdx
