# DataFast goals versus page views, and when you need neither

> Page views are free and automatic. Goals cost events and need a name, a reason and a side of the network. A decision table, the naming rule, and what never to put in a goal.

A new DataFast install tends to go one of two ways. Nobody adds a goal, so the
dashboard can say where visitors came from but not what they did. Or someone
adds forty, and the monthly event quota is gone by the 12th.

The fix is knowing what each one is for.

## Page views: already done

The script records a page view on load, and on every client-side navigation:
it listens to `history.pushState` and `popstate`. That covers Next.js App
Router links. You do not need a `usePathname` effect, and adding one double
counts.

So these need no code at all:

- "How many people see the pricing page?" Filter by page.
- "Where do visitors who read the docs come from?" Filter by page, then look at
  referrers.
- "Which landing page converts?" Revenue by entry page. That is the point of
  the product.

## Goals: things a URL cannot tell you

A goal is an action on a page, or an outcome on the server:

| Question | Page view or goal |
|---|---|
| Did they open pricing? | Page view |
| Did they click "Start trial" on pricing? | Goal, browser: `checkout_started` |
| Did they create an account? | Goal, server: `signup_completed` |
| Did they finish onboarding step 3? | Goal, server: `onboarding_step_completed` with `step: 3` |
| Did they pay? | Neither. DataFast reads payments from your provider |

That last row matters. Revenue comes from the connected payment provider, with
attribution from checkout metadata. A `purchase_completed` goal with an amount
is a second, worse copy.

## Name goals like records

`object_verb`, past tense, snake_case:

```
checkout_started
signup_completed
project_created
newsletter_subscribed
```

DataFast accepts lowercase letters, digits, `_`, `-` and `:`, up to 64
characters. That is permission, not a convention. Pick one and enforce it, or
in a year you have `signup`, `sign-up` and `signup:done` as three series.

Never put a value in the name. `plan_pro_bought` and `plan_team_bought` are one
goal with a `plan` property. Otherwise every new plan breaks every funnel.

Stay away from DataFast's reserved names: `payment`, `free_trial`,
`trial_started`, `trial_converted`, the `subscription_*` family and
`identify`. It sends those itself once a payment provider is connected.

## Make the catalogue a type

```ts
export interface GoalCatalogue {
  checkout_started: { plan: string; interval: "month" | "year" };
  signup_completed: { method: "email" | "oauth" };
}

export function trackGoal<N extends keyof GoalCatalogue>(
  name: N,
  properties: GoalCatalogue[N],
): void {
  window.datafast?.(name, toGoalMetadata(properties));
}
```

Now `trackGoal("signup")` does not compile. The second spelling of a goal is a
type error in the editor, not a mystery series in the dashboard.

## Properties: 10 strings, no people

DataFast keeps at most 10 parameters per goal, keys in lowercase, values up to
255 characters, all stored as strings. Use them for things you will filter by:
plan, source, step, method.

DataFast's own examples pass `email` and `name` as goal parameters. Do not.
Goal parameters show up for everyone with dashboard access, forever. If you
need to find a person, use `identify` with your database user id, and keep the
email in your database.

## Where to fire it

- **Browser** for intent: clicks, forms opened, a screen seen. Some of it will
  be lost to blockers and closed tabs, and that is fine for intent.
- **Server** for facts: an account row, a saved step. Use the Goals API after
  the write. It is complete, and a user cannot fake it from DevTools.

Never both for the same name. Two copies of one event double the count, and
nothing can tell them apart later.

## A budget, not a wishlist

Every goal is billed as an event. Before adding one, write the question it
answers in one sentence. "Which channels bring people who finish onboarding?"
earns a goal. "Might be useful later" does not.

---

Agentic Boilerplate: A Next.js repo your agent already knows. Free during launch, then $99 once.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
