Documentation

Agent-operated

Give your agent the job. Keep control of the account.

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.

01 — The purpose

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.

02 — Start here

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 doesYou approveLandingana 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.

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.

03 — Agent access

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:

SurfaceURL
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.

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:

ToolRequired scopeInputBehavior
setup_sitesites:writeoriginNormalizes 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_sitessites:readOptional cursorReturns at most 20 owned sites per page with tracking state, last activity, plan, site allowance, and current-month event usage.
read_analyticsanalytics:readsite_id, optional range, optional detailReturns 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.

04 — What it measures

Overview

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

SignalWhat it means
PageviewAn initial page load or a URL-changing history.pushState, history.replaceState, or browser back/forward navigation.
ClickA link, button, or element explicitly labeled with data-track.
SignupA 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.

What an event can contain

EventBrowser dataIngest context
PageviewPath, external referrer, UTMs, and browser languageDaily visitor, location when available, browser, OS, and device
ClickPath, label, and destination URLDaily visitor and device context
SignupPath and submitted emailDaily 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.

05 — Manual install

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:

TypeScript
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;

06 — Reference

Complete configuration

Script attributes

AttributeDefaultBehavior
srcRequiredLoads the hosted tracker or a first-party proxy. The default event endpoint is derived from this URL.
deferRecommendedLets HTML parsing finish before a conventional script tag executes. It is included in generated snippets.
data-siteRequiredPublic site ID. A missing or empty value disables the tracker.
data-lana-modeAutomaticSet exactly to opt-in to require explicit click and signup markers.
data-includeAll pathsComma-separated exact paths and /* descendant patterns. Applies to every event type.
data-excludeNo pathsComma-separated exact paths and /* descendant patterns. Takes precedence over data-include.
data-endpointScript origin plus /api/eventRelative or absolute HTTP(S) event URL. Invalid values fall back to the default endpoint.
data-debugOffAttribute presence bypasses the tracker's local-host skip. The collector still requires a site registered to the exact local origin.

Element and form attributes

AttributePlace it onBehavior
data-trackAny clickable elementMakes the element trackable and supplies a stable label. In opt-in mode, every tracked click requires it.
data-capture="false"FormDisables email signup capture in automatic mode.
data-capture="true"FormEnables signup capture in opt-in mode when a filled email input exists.
data-lana-ignoreElement or ancestorSuppresses click and signup capture in the subtree. It always wins and does not suppress pageviews.

Automatic versus opt-in mode

BehaviorAutomaticOpt-in
Initial and SPA pageviewsAutomaticAutomatic
Link and button clicksAutomaticRequire data-track
Email form submissionsAutomatic unless disabledRequire data-capture="true"
Ignored subtreeAlways excludedAlways excluded

07 — Control

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>

PatternMatchesDoes not match
/pricing/pricing/pricing/enterprise
/docs/*/docs and descendants/docs-old
/Homepage onlyAny 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.

08 — Data model

Events and data

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

FieldApplies toNotes
PathAll eventsCurrent pathname, up to 512 characters.
VisitorAll eventsAnonymous site-scoped hash derived with a salt that rotates daily.
Referrer and UTMsPageviewsSame-host referrers are excluded. External referrers are normalized to hostnames; source, medium, and campaign are retained.
Click label and URLClicksLabel 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.
EmailSignupsValid emails are normalized to lowercase in the signup list.
Location and deviceAll eventsCountry, 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.

09 — Read the signal

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.

KPIDefinition
VisitorsDistinct daily visitor hashes among pageviews
PageviewsStored pageview events
SignupsStored signup events
Signup rateSignups 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.

10 — Site lifecycle

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 originsDifferent origins
https://example.com and https://www.example.comhttp://example.com and https://example.com
https://example.com and explicit port :443https://app.example.com and https://example.com
One leading www. label and the otherwise identical hostnameDefault and non-default ports

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.

11 — Plans

Pricing and limits

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

PlanPriceSitesMonthly event allowance
Free$0110,000
Founding Pro$9 monthly or $90 yearlyUnlimited100,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.

12 — Support

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.

Ready to hand off the setup?

Give your agent the target domain and point it at auth.md. You approve the connection; it handles the supported setup and analytics workflow.

Start with an agent