# Landingana documentation

> Landingana is a startup-idea validation tool built to be operated by coding agents. One hosted script records pageviews, meaningful clicks, and submitted email signups without cookies or browser storage on the tracked site.

This is the canonical product manual for people and agents; coding agents should read this Markdown source instead of scraping the rendered documentation page. With the user's explicit approval, an agent can register or reuse a site, retrieve the exact tracking install, check activity, and read bounded aggregate analytics through MCP. Start with the agent path below; use the manual path when a public site ID and registered origin were already supplied. The human dashboard and one-line manual install remain available at every step.

## Why Landingana

AI has made me capable of building more software than I can sensibly choose to build. With LLMs, coding agents, and the development harnesses around them, the cost of getting an idea in front of people has collapsed. I can go from a product promise to a credible landing page—with copy, a form, analytics, and a deployment—in minutes or hours.

That changes the constraint. I rarely need help finding time to build another thing. **Focus is hard, not time management.** The difficult question is not whether I can fit another build into the week. It is whether this idea deserves the week at all.

When building feels this easy, it is tempting to mistake momentum for evidence. I can spend days turning an idea into convincing software without learning whether anybody wants it. Before I commit to the product, I want some reason to believe the promise matters to somebody besides me.

### How I test an idea

My test is simple. I create a landing page that explains the idea and gives the visitor one real action to take. They can leave an email address, join the first launch, create an initial account, or sign up for a free offering. Then I send real traffic to the page and watch what people do.

Those actions are not equally strong signals. Creating an account asks more than joining a launch list. What matters at this stage is that each asks the visitor to move beyond passive interest and volunteer a way to continue.

The landing page is cheap. The willingness to act is the signal.

Pageviews tell me that people reached the promise. Deliberately tracked clicks show where it prompted a meaningful next action. A signup is stronger: somebody accepted the friction of sharing an email address or creating an account for the chance that the promise becomes real.

If the people I intended to reach arrive and nobody signs up, that is useful too. It is evidence against the current combination of audience, promise, and offer before I commit to a full build. It does not automatically kill the underlying idea. It tells me to change the test or stop.

### The threshold I use

A signup does not prove that the idea will become a successful company. It does not prove that people will pay, keep using the product, or recommend it. It is the signal I have chosen for a narrower decision: whether this idea has earned the next round of my effort.

I do not need a universal conversion benchmark for that decision. I need to see whether the offer earns signups from the people I intended to reach, in the context of how many arrived and where they came from. That is more useful to me than a large analytics surface full of measurements that do not change what I build next.

### Why I built Landingana

I built Landingana for this exact loop: launch a focused promise, send it traffic, observe the few interactions that matter, and decide whether the response is strong enough to build the product behind it.

Landingana uses analytics, but it is designed around a founder's decision rather than a mature company's reporting needs. Its job is not to measure everything. Its job is to make one early experiment quick to instrument and easy to read: did the people I hoped to reach merely visit, did they act, and did any of them choose to continue?

The dashboard is not the point. The point is shortening the path from a product promise to an evidence-backed decision: build the next version, revise the test, or walk away.

AI gives me the leverage to make almost anything. I built Landingana to help me decide what is worth making.

## Quick start

The default setup path is agent-operated: give a coding agent the target domain and let it discover the current authorization flow from `auth.md`.

| Your agent does | You approve | Landingana enforces |
| --- | --- | --- |
| Discovers the flow, registers the connection, sets up the site, installs the snippet, and reads aggregate results. | The connection in Landingana after signing in with the same email used by the agent. | Account ownership, scoped tools, origin binding, expiring credentials, and dashboard revocation. |

There are two supported installation paths:

- **Autonomous setup:** start at `https://www.landingana.com/auth.md`, complete the user-claimed `service_auth` flow, then call `setup_site` through the Landingana MCP.
- **Manual setup:** use a public site ID and registered origin supplied from the Landingana dashboard.

For autonomous setup, the agent registers the connection and hands off one
account-ownership step to the user:

1. Fetch `/auth.md` and register with the user's email as `login_hint`.
2. Use browser or computer control to open the verification link when available. Pause for the user's credentials, passkey, magic link, one-time code, or explicit approval; never ask the user to send secrets through chat.
3. After the user authenticates, reviews the Landingana claim screen, and explicitly approves continuing, the agent may enter the six-digit claim code it already received. Without browser control, show the link and code together so the user can complete the claim on Landingana.
4. Poll the documented claim grant until Landingana returns an access token and identity assertion.
5. Connect to `https://www.landingana.com/mcp` with the bearer token and call `setup_site` with the target web origin.
6. Return to the target repository. Inspect routes and forms, then add one Landingana loader at the narrowest shared seam for intended public pages. Keep authentication, account, checkout, dashboard, admin, and other private routes out of pageview collection with a narrower layout or `data-include`/`data-exclude`; interaction controls alone do not suppress pageviews.
7. Capture the site's `list_sites.last_event_at` baseline. If deployment and a live visit are authorized and in scope, visit the exact registered origin, trigger an intended event on a controlled public route, and confirm that the timestamp advanced or stored activity appeared in the dashboard. Treat an advance as integration evidence rather than proof of one specific event on a busy site. Otherwise report runtime verification as incomplete. Use `read_analytics` for bounded aggregate results.

### Prefer not to connect an agent?

Manual installation can proceed without product credentials once you or an agent has two values:

- The public Landingana site ID, such as `a1b2c3d4`.
- The registered site origin, such as `https://example.com`.

The site ID is intentionally public and belongs in client HTML. It is not a secret or API key. Never invent a site ID: if one has not been supplied, obtain it from the site's Landingana dashboard before editing the target application.

1. Find the narrowest shared document, head, or layout that covers only the intended public pages.
2. Audit every route and email form covered by that seam. Keep private-route pageviews out with a narrower layout or `data-include`/`data-exclude`. Use opt-in mode or element/form controls separately to narrow clicks and signup capture on included pages.
3. Add the generated script exactly once. Preserve `defer`, the supplied `data-site` value, documented privacy controls, unrelated analytics, and application behavior.
4. If Content Security Policy is present, allow the tracker in the controlling `script-src` or `script-src-elem` directive and the collector in `connect-src` without adding `unsafe-inline` or `unsafe-eval`.
5. Run the target project's checks and verify that an intended rendered page contains exactly one Landingana loader.
6. If a live visit is authorized and in scope, visit the registered production or preview origin and confirm stored activity in the dashboard. A rendered tag, passing build, deployment, network request, or HTTP `202` is not storage proof. If no live check is available, report runtime verification as incomplete.

**Basic HTML installation**

```html
<script defer src="https://www.landingana.com/l.js" data-site="YOUR_SITE_ID"></script>
```

Replace `YOUR_SITE_ID`; do not copy that placeholder into a real deployment.

> **Local development**
>
> The tracker skips `localhost` and `127.x.x.x` by default. `data-debug` bypasses only that client-side skip; it does not bypass server-side origin binding. It can exercise client emission, but `202` still does not prove storage. If the plan's site allowance permits, use a separate site registered to the exact local protocol, hostname, and port. Free users who already registered production should verify storage on that deployed origin instead. A wrong origin can be corrected from its site page before the first event.

### Next.js App Router

Prefer a layout in the public route group. If the root layout is the only shared seam, add route filters so private pages do not emit pageviews. Next.js forwards custom data attributes to the rendered script element.

```tsx
import Script from "next/script";

<Script
  src="https://www.landingana.com/l.js"
  data-site="YOUR_SITE_ID"
  data-exclude="/login/*,/account/*,/checkout/*,/dashboard/*,/admin/*"
  strategy="afterInteractive"
/>
```

### Content Security Policy

For the hosted installation, the policy that governs the page must allow
`https://www.landingana.com` in `script-src` or `script-src-elem` and in
`connect-src`. A first-party proxy uses the tracked site's own script and
connection origins instead. Preserve existing nonces and strict directives; do
not make the policy broadly permissive with `unsafe-inline` or `unsafe-eval`
to install analytics.

## Agent authentication and MCP

Landingana's remote MCP is intentionally small. Authentication is additive to the existing Better Auth login system: people continue to sign in with GitHub or a magic link, while agents use AuthMD's user-claimed `service_auth` flow. Landingana does not accept anonymous agent registration or incoming provider identity assertions.

### Start with `auth.md`

The agent walkthrough is:

```text
https://www.landingana.com/auth.md
```

It contains current endpoint URLs, grant names, polling rules, and recovery instructions. Supporting discovery endpoints are also public:

| Surface | URL |
| --- | --- |
| Protected resource metadata | `/.well-known/oauth-protected-resource` |
| Authorization server metadata | `/.well-known/oauth-authorization-server` |
| Public signing keys | `/.well-known/jwks.json` |
| Agent registration | `/agent/identity` |
| Claim-code replacement | `/agent/identity/claim` |
| Token exchange | `/oauth2/token` |
| Token revocation | `/oauth2/revoke` |
| Streamable HTTP MCP | `/mcp` |

Register with a valid email login hint:

```http
POST /agent/identity
Content-Type: application/json

{"type":"service_auth","login_hint":"user@example.com"}
```

The registration response is deliberately account-existence-agnostic. It does not reveal whether that email already belongs to a Landingana user. The response includes a claim token plus a verification URL and six-digit user code. Treat `claim_token` as private bearer material: never log, render, or show it to the user. Surface only the intended `verification_uri` and `user_code`; possession of the outer token lets the agent poll for credentials after approval.

With browser or computer control, the agent opens the verification link and
pauses whenever Landingana needs credentials, a passkey, magic-link access, a
one-time login code, or explicit approval. After the user authenticates,
reviews the claim screen, and approves continuing, the agent may enter the
six-digit claim code it already received. Without browser control, the agent
shows the link and code together so the user can complete the claim on
Landingana. An existing account binds the registration to the same user,
sites, plan, and usage. A new user is created only through the normal human
sign-in flow. No usable API credential or site is created before the
authenticated user confirms the claim, and the verified account email must
match the original login hint.

> **Keep the code on Landingana**
>
> The claim code is already known to the registering agent; account credentials, passkeys, magic links, and one-time login codes are not. Never ask the user to paste any secret into the harness or chat. Claim attempts expire, are attempt-limited, and can be replaced only while the outer registration remains valid. A replacement response contains a new pair under `claim_attempt`; discard the expired verification URL and code, then repeat the claim ceremony with the new values.

### Credential lifecycle

The default scopes are `sites:read`, `sites:write`, and `analytics:read`.

- Access tokens last one hour and are sent as `Authorization: Bearer …` to `/mcp`.
- The returned identity assertion lasts 30 days and can be exchanged for another access token using the JWT bearer grant documented in `/auth.md`. This renews access from the assertion; it is not a refresh-token flow.
- Landingana does not issue refresh tokens. When the assertion expires or exchange returns `invalid_grant`, discard the credentials and repeat `service_auth` registration and user claim.
- `/oauth2/revoke` revokes one access token. The user can revoke the entire agent registration—including every token and identity assertion—from the dashboard.

### MCP tools

The MCP is stateless and exposes exactly three scope-gated tools:

| Tool | Required scope | Input | Behavior |
| --- | --- | --- | --- |
| `setup_site` | `sites:write` | `origin` | Normalizes the web origin, creates, recovers, or reuses the user's site idempotently, respects the account's site limit, and returns the exact installation snippet plus whether a legacy row was recovered. |
| `list_sites` | `sites:read` | Optional `cursor` | Returns at most 20 owned sites per page with tracking state, last activity, plan, site allowance, and current-month event usage. |
| `read_analytics` | `analytics:read` | `site_id`, optional `range`, optional `detail` | Returns aggregate analytics for an owned site. Ranges are `24h`, `7d`, or `30d`; detail is `summary` or `full`. |

`read_analytics` summary mode returns visitors, pageviews, signups, and signup rate. Full mode additionally returns at most 30 time buckets and five rows for each ranked breakdown: pages, referrers, countries, devices, browsers, and clicks. Returned click labels are bounded and email-redacted; when the entire value is URL-shaped, credentials, query strings, fragments, and contact schemes are removed. This read-time pass also protects legacy rows created before write-time sanitization.

The MCP never returns signup email addresses, raw events, visitor hashes, or signing material. It does not expose billing, checkout, deletion, raw SQL, token management, documentation resources, prompts, or extra tools. Fetch `/llms.txt`, `/llms-full.txt`, or `/docs.md` directly when more product guidance is needed.

The public `/api/event` collector remains a separate write-only browser telemetry endpoint. It is not an authentication or account-management API.

## Overview

Landingana helps determine what turns a landing-page visit into intent. One hosted script records:

| Signal | What it means |
| --- | --- |
| Pageview | An initial page load or a URL-changing `history.pushState`, `history.replaceState`, or browser back/forward navigation. |
| Click | A link, button, or element explicitly labeled with `data-track`. |
| Signup | A submitted form containing a filled `input[type="email"]`. |

The tracking script has no runtime dependencies and does not use cookies, `localStorage`, or other browser storage. It sends events with `navigator.sendBeacon`, falls back to a keepalive `fetch`, and swallows collection errors so analytics cannot break the host page.

> **Privacy model**
>
> Landingana derives a pseudonymous site-scoped visitor hash from request and browser context. Its server-side salt rotates daily, so the same person may count again on another UTC day. Nothing is persisted in the visitor's browser by the tracking script. This reduces persistent tracking; it is not a legal-compliance guarantee for every site or jurisdiction.

### What an event can contain

| Event | Browser data | Ingest context |
| --- | --- | --- |
| Pageview | Path, external referrer, UTMs, and browser language | Daily visitor, location when available, browser, OS, and device |
| Click | Path, label, and destination URL | Daily visitor and device context |
| Signup | Path and submitted email | Daily visitor and device context |

External referrers are normalized to hostnames before storage. Signup capture observes the browser's submit event. It does not wait for a form provider to confirm success, call `preventDefault`, or change normal submission behavior.

## Install script

The generated script is the complete default installation. `data-site` is required; the tracker exits immediately when it is missing or empty.

### Configured installation

This example opts into explicit interaction capture, limits tracking to selected public routes, excludes account routes, and sends data through first-party proxy paths.

```html
<script
  defer
  src="/_landingana/l.js"
  data-site="YOUR_SITE_ID"
  data-lana-mode="opt-in"
  data-include="/,/pricing,/docs/*"
  data-exclude="/dashboard/*,/login/*"
  data-endpoint="/_landingana/event"
></script>
```

### First-party proxy mode in Next.js

Proxy both the script and event endpoint through the tracked domain. Proxying only events does not help if a blocker prevents the third-party script from loading; proxying only the script without setting `data-endpoint` sends events to the wrong relative path.

Use the configured script above together with these rewrites:

```ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  async rewrites() {
    return [
      {
        source: "/_landingana/l.js",
        destination: "https://www.landingana.com/l.js",
      },
      {
        source: "/_landingana/event",
        destination: "https://www.landingana.com/api/event",
      },
    ];
  },
};

export default nextConfig;
```

> **Preserve request context**
>
> A first-party proxy must preserve the browser `Origin`, `User-Agent`, client-IP forwarding, and any geographic headers Landingana is expected to use. Verify the rewrite behavior on the actual hosting platform.

## Complete configuration

### Script attributes

| Attribute | Default | Behavior |
| --- | --- | --- |
| `src` | Required | Loads the hosted tracker or a first-party proxy. The default event endpoint is derived from this URL. |
| `defer` | Recommended | Lets HTML parsing finish before a conventional script tag executes. It is included in generated snippets. |
| `data-site` | Required | Public site ID. A missing or empty value disables the tracker. |
| `data-lana-mode` | Automatic | Set exactly to `opt-in` to require explicit click and signup markers. |
| `data-include` | All paths | Comma-separated exact paths and `/*` descendant patterns. Applies to every event type. |
| `data-exclude` | No paths | Comma-separated exact paths and `/*` descendant patterns. Takes precedence over `data-include`. |
| `data-endpoint` | Script origin plus `/api/event` | Relative or absolute HTTP(S) event URL. Invalid values fall back to the default endpoint. |
| `data-debug` | Off | Attribute presence bypasses the tracker's local-host skip. The collector still requires a site registered to the exact local origin. |

### Element and form attributes

| Attribute | Place it on | Behavior |
| --- | --- | --- |
| `data-track` | Any clickable element | Makes the element trackable and supplies a stable label. In opt-in mode, every tracked click requires it. |
| `data-capture="false"` | Form | Disables email signup capture in automatic mode. |
| `data-capture="true"` | Form | Enables signup capture in opt-in mode when a filled email input exists. |
| `data-lana-ignore` | Element or ancestor | Suppresses click and signup capture in the subtree. It always wins and does not suppress pageviews. |

### Automatic versus opt-in mode

| Behavior | Automatic | Opt-in |
| --- | --- | --- |
| Initial and SPA pageviews | Automatic | Automatic |
| Link and button clicks | Automatic | Require `data-track` |
| Email form submissions | Automatic unless disabled | Require `data-capture="true"` |
| Ignored subtree | Always excluded | Always excluded |

## Targeting and capture

### Target specific pages

Add a comma-separated path allowlist to the script. Matching uses `location.pathname`, so query strings and fragments do not affect a rule.

```html
<script
  defer
  src="https://www.landingana.com/l.js"
  data-site="YOUR_SITE_ID"
  data-include="/,/pricing,/docs/*"
  data-exclude="/docs/private/*"
></script>
```

Use `data-exclude` by itself to track every path except selected routes. If both attributes are present, an excluded path is never tracked.

```html
<script
  defer
  src="https://www.landingana.com/l.js"
  data-site="YOUR_SITE_ID"
  data-exclude="/login/*,/dashboard/*"
></script>
```

| Pattern | Matches | Does not match |
| --- | --- | --- |
| `/pricing` | `/pricing` | `/pricing/enterprise` |
| `/docs/*` | `/docs` and descendants | `/docs-old` |
| `/` | Homepage only | Any other path |

### Label only the actions that matter

```html
<button data-track="Hero signup CTA">Start free</button>

<form data-capture="true">
  <input type="email" name="email" required />
  <button type="submit" data-track="Join waitlist">Join waitlist</button>
</form>

<section data-lana-ignore>
  <!-- Clicks and email submissions here are ignored. -->
</section>
```

Click labels use the `data-track` value first, then trimmed element text, and are limited to 80 characters. Prefer stable semantic labels so dashboard reporting survives visible copy changes.

> **SPA navigation**
>
> Landingana records a pageview when `history.pushState`, `history.replaceState`, or browser back/forward changes `pathname + search`. State-only calls, repeated URLs, and hash-only changes do not create duplicate pageviews.

## Events and data

Every tracked interaction is a `pageview`, `click`, or `signup`. Context is collected only when it helps explain intent.

| Field | Applies to | Notes |
| --- | --- | --- |
| Path | All events | Current pathname, up to 512 characters. |
| Visitor | All events | Anonymous site-scoped hash derived with a salt that rotates daily. |
| Referrer and UTMs | Pageviews | Same-host referrers are excluded. External referrers are normalized to hostnames; source, medium, and campaign are retained. |
| Click label and URL | Clicks | Label up to 80 characters and destination up to 512. New values are email-redacted before storage. Whole URL-shaped values are reduced to a non-credentialed scheme, host, and path; contact schemes are replaced. Prose labels are preserved, so avoid embedding sensitive query strings in custom labels. |
| Email | Signups | Valid emails are normalized to lowercase in the signup list. |
| Location and device | All events | Country, region, and city when platform headers exist; browser, OS, and device derived from `User-Agent`. |

Detected bots, invalid payloads, unknown or paused sites, origin mismatches, rate-limited requests, and over-quota traffic are silently dropped. The collector still returns `202 Accepted` to avoid leaking whether a site ID exists and to avoid breaking a visitor's page.

**A `202` response proves only that the collector handled the request. It does not prove that the event passed validation or was stored.** Verify storage in the dashboard.

For new ingestion, account quota, per-site usage, an optional signup row, and
the corresponding event are written in one PostgreSQL statement. Invalid
signup email payloads are rejected before quota is claimed, and a write failure
rolls the statement back. Historical counters from before this guarantee are
not retroactively reconciled.

## Dashboard

The account dashboard is the index of experiments. Each site row shows pageviews and signups from the last seven days, then opens the detailed view.

### Time ranges and KPIs

Choose 24 hours, 7 days, or 30 days. The selected UTC window drives the four KPI cards, time series, and ranked breakdowns.

| KPI | Definition |
| --- | --- |
| Visitors | Distinct daily visitor hashes among pageviews |
| Pageviews | Stored pageview events |
| Signups | Stored signup events |
| Signup rate | Signups divided by unique visitors |

### Breakdowns

Top pages, referrers, countries, devices, browsers, and clicks show leading values in the active window. Query results contain up to ten values; the current dashboard presents shorter visible lists for some device and browser breakdowns. Missing referrers appear as direct, and unavailable dimensions appear as unknown.

### Recent signups and CSV

Recent signups shows the newest 50 signups across all time, including email,
path, and relative time. It is not filtered by the chart range. Export CSV
downloads every signup for the site, oldest first, with ISO 8601 UTC
timestamps. Fields are RFC 4180 encoded and spreadsheet formula prefixes are
neutralized.

The detail page checks for updated data every 30 seconds while visible and when
the user returns to it. This is polling, not a streaming or instant-delivery
guarantee. Manual refresh and a retry boundary remain available.

## Site details

### A site is a web origin

Landingana stores the normalized protocol, hostname, and effective port—not paths, credentials, query strings, or fragments. Incoming browser events are accepted only when their `Origin` matches the registered origin after normalization.

| Equivalent origins | Different origins |
| --- | --- |
| `https://example.com` and `https://www.example.com` | `http://example.com` and `https://example.com` |
| `https://example.com` and explicit port `:443` | `https://app.example.com` and `https://example.com` |
| One leading `www.` label and the otherwise identical hostname | Default and non-default ports |

> **Public site ID, private analytics**
>
> The site ID in the script is public by design. Origin matching is a browser admission and noise-reduction boundary: it rejects ordinary cross-origin browser telemetry, but a direct client can supply an HTTP `Origin` header. It is not cryptographic event authentication, and Landingana analytics are not an audit-grade integrity log. Authenticated ownership still protects dashboards, agent reads, and exports.

### Before the first event

The site page shows the exact registered origin, script, and a copyable
coding-agent prompt with privacy-safe placement and stored-event verification
instructions. After events arrive, the analytics view keeps the same
installation information in a persistent disclosure instead of hiding it.
Before the first event, the owner can correct a mistaken protocol, hostname, or
port on that site without consuming another site allowance. Once an
origin-bound site has analytics history, its origin is locked so existing data
cannot be relabeled.

### Legacy sites

Sites created before origin binding have no trusted origin and safely ignore
new events. They never receive a non-working snippet. When an account has no
origin-bound site, normal setup assigns the explicit public URL to the
deterministic oldest legacy row, preserves its site ID and history, and resumes
tracking. `setup_site` reports this as `recovered: true`. An owner can also open
any specific legacy site and assign its public origin explicitly, including a
history-bearing record. If another site already occupies the Free active slot,
that newly connected record remains paused rather than creating a second active
collector.

## Pricing and limits

Both plans contain the analytics product. They differ in total site and monthly event allowances.

| Plan | Price | Sites | Monthly event allowance |
| --- | --- | --- | --- |
| Free | $0 | 1 | 10,000 |
| Founding Pro | $9 monthly or $90 yearly | Unlimited | 100,000 pooled across the account |

Founding Pro is the configured paid plan, but public paid signup may be closed. Do not assume an agent or user can start checkout merely because pricing is documented; use the current dashboard state as the source of truth.

### What counts

Each event stored through the current atomic ingestion path consumes one unit.
Pro usage is pooled across the account: one site can use the allowance or many
sites can share it. Unlimited refers to sites, not traffic.

At the limit, Landingana stops storing new events until the next UTC month or a plan change raises the ceiling. There are no automatic overages, and dropped events are not replayed.

### Downgrades and payment grace

When Pro access ends, historical data and every site are preserved. Landingana
keeps the oldest origin-bound site active and pauses the rest; if every row is
legacy, it falls back to the deterministic oldest row. Active and trialing
subscriptions receive Pro access; past-due subscriptions receive seven days of
grace from the new billing period's start.

## Troubleshooting and FAQ

### I installed the script, but no events appear

Check the exact site ID, registered protocol/hostname/port, `data-include`
allowlist, `data-exclude` blocklist, monthly usage, and whether the site is
paused. Remember that one leading `www.` label is normalized as equivalent.
For local storage, `data-debug` still needs a site registered to the exact local
protocol, hostname, and port. Create that extra site only when the plan allows;
otherwise verify the registered deployed origin. A `202` response does not
prove that an event was stored.

### Pageviews appear, but clicks do not

Automatic mode covers links and buttons. Opt-in mode requires `data-track`. Also check whether the element or an ancestor has `data-lana-ignore`.

### My form submits, but no signup appears

The form needs a filled `input[type="email"]`. Remove `data-capture="false"` in automatic mode, add `data-capture="true"` in opt-in mode, and check ignored ancestors. Signup capture records the submit attempt rather than waiting for a remote form provider to report success.

### Why did only one site stay active after cancellation?

Free includes one site for new setup. If a Pro account later returns to Free,
Landingana preserves every site and its history, keeps the oldest usable
origin-bound site active, and pauses the rest. Restoring Pro restores
collection across them.

### What happens at the monthly limit?

New events are dropped without affecting the visitor's page. Collection resumes next UTC month or after a plan change raises the same month's ceiling. There are no overage fees or retroactive recovery.

### Can a blocker stop Landingana?

Yes. First-party mode can improve compatibility, but proxy both the script and endpoint and preserve request headers. No analytics tool can guarantee collection against every blocker.

### Does Landingana use cookies?

The public tracking script does not use cookies, `localStorage`, or browser storage. The authenticated Landingana application has its own session behavior. Review the tracked site's complete data practices and applicable requirements before making legal claims.

### Can an agent create sites or read analytics programmatically?

Yes. Start at `/auth.md`, complete the user-claimed `service_auth` flow, and use the authenticated `/mcp` endpoint. `setup_site`, `list_sites`, and `read_analytics` are the complete MCP surface. Do not infer additional management operations from the public event collector: `/api/event` is a write-only browser telemetry endpoint and deliberately returns the same `202` response for accepted and discarded input.

### Can an agent read signup email addresses?

No. MCP analytics are aggregate-only and do not return signup emails, raw event rows, or visitor hashes. Signup email lists and CSV export remain authenticated dashboard workflows for the human account owner.

### The agent's assertion expired. Can it use a refresh token?

No refresh token is issued. Discard the expired credentials and restart at `/agent/identity` so the user can claim a new `service_auth` registration. If an access-token request is temporarily rate-limited, honor the response's `Retry-After` value instead of starting duplicate registrations.
