We’re live!
betterdata
THE BETTERDATA GUIDE

Make every visit count.

Install your tracker, understand your traffic, and connect the actions that matter.

Install tracking

Add your website, copy its script from settings, install it inside your website’s head, then open your website. Tracking health confirms actual accepted events.

<script defer src="https://YOUR-TRACKER-HOST/track.js"
  data-site="YOUR_SITE_ID" data-privacy="persistent"></script>

For Next.js, place the script in the root layout. For WordPress, use the plugin download in setup. For Shopify, theme installation tracks storefront activity; checkout tracking needs an explicit integration.

Consent and identity

Persistent mode uses localStorage. Use data-privacy="memory" to keep the ID only for the current page lifetime, or data-consent="required" to wait for explicit consent.

betterdata.consent(true);
betterdata.track('pricing_click');
betterdata.goal('signup');
const visitorId = betterdata.visitorId();

Do not send names, emails, payment card details or sensitive data in event properties. Consent requirements depend on your website and jurisdiction. Read the identity and consent guide → Connect domains →

Measurement

Sessions end after 30 minutes without observed activity. Online means activity in the last 10 minutes. Bounce reports completed single-page sessions without a custom event or goal. Session duration measures observed activity. Source breakdowns count pageviews; unique visitors are counted across the full period.

UTMs are optional. External referrers can identify sources; when both are absent, the result is Direct / unknown. Country and city are approximate. Local development may have no location metadata.

Razorpay revenue attribution

Open website settings and retrieve the Razorpay webhook URL and secret. In your Razorpay dashboard, subscribe to payment.captured, payment.failed and refund.processed. When creating a payment server-side, set the payment’s notes.betterdata_visitor_id to the browser’s anonymous visitor ID. Verify the notes reach the payment entity for your checkout flow. Payments without a matching ID remain unattributed.

Webhooks are checked against the raw body with HMAC-SHA256. Duplicate receipts and refunds are recorded once. Razorpay cannot deliver directly to localhost; a public staging endpoint is needed for provider delivery tests.

Betterdata subscriptions

Set RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET and RAZORPAY_PLANS in local .dev.vars or deployed Worker secrets. Configure subscription webhooks at /api/billing/webhook. Keep revenue webhooks separate from billing webhooks.

RAZORPAY_PLANS={"starter_10000_monthly":{"id":"plan_REPLACE","amountMinor":90000,"currency":"INR"}}

This is a configuration example, not an approved INR price. The server checks the amount and currency against Razorpay before creating checkout. INTEGRATION_SIGNING_KEY signs per-site webhook secrets; generate a random private value and retain it securely.

API and exports

Create a site API token in website settings. Keep it server-side. GET /api/analytics?site=SITE_ID&range=30 accepts an analytics:read bearer token. Date and audience filters are shared by the dashboard and CSV export. Exports over 10,000 events require a narrower range.

Primary KPI and exclusions

Website Settings → Measurement controls lets you select a registered goal as your primary KPI and exclude paths, hostnames or country codes. Wildcards are anchored: /admin/* excludes descendants, not /administrator. Exclusions affect new analytics only; existing events and signed payments remain intact.

Section visibility goals

<section data-bd-goal="pricing_view" data-bd-threshold="0.5" data-bd-dwell="1000">Pricing</section>

Register pricing_view in Goals first. The browser records the goal once per URL after the section remains sufficiently visible for the configured dwell time. Hidden tabs and absent consent do not qualify. Dynamically inserted sections and SPA navigation are supported.

Release annotations

Create a site token with notes:write, keep it in your CI secrets, and POST /api/notes with siteId, body, externalId (for example a Git commit SHA) and an optional ISO createdAt. The release identifier is deduplicated within its site. Notes in the selected date range appear as chart markers; hover for details. This uses CI deployment metadata, not a GitHub App or repository access. An annotation shows timing, not proof that a release caused a traffic change.

Cloudflare deployment

Use separate staging and production Workers, D1 databases and GitHub OAuth apps. Generate Prisma, apply local migrations, type-check, build with vinext, test the compiled Worker, then follow the repository’s deployment runbook. Deployment remains a separate release action.

Razorpay webhook documentation ↗