Skip to content

SDK Integration

Add the Pomelo tracking script to your site.

Mode note: Pomelo is moving toward a Strict by default / Extended by configuration model. The default baseline is audience measurement with minimal collection. Acquisition enrichments, richer custom events, and processing that increases collection belong to explicit Extended configuration and should be documented as such. Customer-, account-, or shop-facing views are an organization and access capability, available depending on the plan and configuration.

Verification is optional. You can install the script and start collecting data immediately with the siteId.

When you create the site in the dashboard, enter the exact hostname where the script will run, for example app.example.com. If you want to track the full domain and its subdomains, confirm that scope during site setup.

The dashboard gives you a single script tag to copy. Endpoint overrides are reserved for internal or advanced environments and are not part of the default installation.

The site settings in Pomelo are the authoritative source for:

  • the active collection profile (Strict or Extended)
  • localhost recording
  • UI, forms, and errors autocapture

Bounded UI/form action capture can be enabled in Strict. Broader autocapture, auto-detected labels, and error capture require explicit Extended-compatible configuration; the script gates error capture to Extended.

At startup, the SDK fetches this runtime configuration from Pomelo with the site id in the script tag. If runtime configuration cannot be confirmed, the SDK uses a strict-safe fallback. The server-side ingest path remains authoritative in every case.

Changing the profile in Settings -> Sites -> Collection only affects future collection. It does not enrich past events retroactively.

If you are migrating an older install, use the Consumer Migration Guide.

When you create a site in Pomelo, enter the real hostname where the script will be installed.

Pomelo then asks what you want to track:

  • This hostname only

  • The domain and its subdomains

  • Use example.com or www.example.com if you want one site that covers the domain and its subdomains.

  • Use shop.example.com if you want that subdomain to be tracked as a separate site.

  • Use the exact hostname for shared platforms such as tenant.wixsite.com, not the platform root domain.

Ownership verification stays optional and is only shown when Pomelo can generate a valid DNS challenge for that site scope.

If the site stays in exact-hostname mode, Pomelo keeps collecting data normally and shows DNS verification as unavailable for that site type.

For a single-hostname marketplace such as market.example.com/demo-shop, keep one site for the shared product and use tenantId / tenantSlug for the current shop. See Multi-tenant analytics and the Multi-tenant guide.

<script
defer
src="https://cdn.pomeloanalytics.com/latest/analytics.js"
data-site-id="YOUR_SITE_ID"
></script>

Copy this tag from the dashboard and paste it in your site head. Do not add collection profile, autocapture, or tenant settings to the snippet.

Framework examples should keep the same contract: load analytics.js and pass only the site id.

import type { ReactNode } from 'react';
import Script from 'next/script';
export default function RootLayout({
children,
}: {
children: ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Script
id="pomelo-analytics"
src="https://cdn.pomeloanalytics.com/latest/analytics.js"
data-site-id="YOUR_SITE_ID"
strategy="afterInteractive"
/>
</body>
</html>
);
}

Stable, semantic identifier for clicks and forms. Becomes el_id in events. When combined with a scope, produces scope/id.

<a href="/signup" data-analytics-id="cta:hero_primary">Get started</a>

Naming convention: lowercase, colons for namespacing (e.g. cta:hero_primary, nav:pricing, form:contact).

Sanitization: max 100 characters, charset [a-zA-Z0-9_\-.:/ ] only. Dropped entirely if PII is detected.

Explicit human-readable label for a click target. Use when the auto-detected label (text, aria-label) is incorrect or missing. Becomes el_label with el_label_src = "data".

<a
href="/signup"
data-analytics-id="cta:hero"
data-analytics-label="Get started free"
>
<span class="icon">🚀</span> Get started — it's free!
</a>

Sanitization: max 80 characters. Dropped if PII is detected.

Group related elements under a section prefix. Produces el_id = "scope/id" in events.

<nav data-analytics-scope="nav">
<a href="/pricing" data-analytics-id="pricing">Pricing</a>
<!-- el_id = "nav/pricing" -->
</nav>

Same sanitization rules as data-analytics-id.

Exclude a subtree from all tracking (clicks, forms). Use on admin panels, debug toolbars, or sensitive UI zones.

<div data-analytics-ignore>
<a href="/admin">Admin panel</a>
<!-- This click will NOT be tracked -->
</div>
GoodBad (dropped by SDK)
cta:signupuser-alice@company.com (email)
nav:pricingbtn-550e8400-e29b-41d4-... (UUID)
form:contactorder-1234567890123 (long digits)
header:logoa]b<c (unsafe characters)
checkout-step-2101+ characters (overflow)
GoodBad (dropped by SDK)
Add to cartContact alice@example.com (email)
Download PDFCall +33 6 12 34 56 78 (phone)
GoodBad (dropped by SDK)
header:navuser:550e8400-... (UUID)
pricingsession:sk_live_abcdefg... (token)

Use stable business identifiers and tag the element that matches the interaction you want to count.

What you want to measureWhere to add the tagEvent emittedAPI filter
Click on an internal CTAClickable element such as <a> or <button>ui.clickaction_family=instrumentation + action_key=instrumentation::...
Click to an external siteOutbound <a> elementoutbound.clickaction_family=outbound + action_key=outbound::...
Validated form submission<form> elementform.submitaction_family=forms + action_key=forms::...
<a href="/demo" data-analytics-id="cta:hero_primary">Request a demo</a>

Query it with:

Terminal window
curl -sS -G "https://api.pomeloanalytics.com/v1/reports/actions" \
-H "Authorization: Bearer $POMELO_API_TOKEN" \
--data-urlencode "site_id=site_123" \
--data-urlencode "from=2026-02-01" \
--data-urlencode "to=2026-02-28" \
--data-urlencode "action_family=instrumentation" \
--data-urlencode "action_key=instrumentation::cta:hero_primary"
<a
href="https://partner.example/listing/123"
data-analytics-id="partner:directory"
>
View listing
</a>

Query it with:

Terminal window
curl -sS -G "https://api.pomeloanalytics.com/v1/reports/actions" \
-H "Authorization: Bearer $POMELO_API_TOKEN" \
--data-urlencode "site_id=site_123" \
--data-urlencode "from=2026-02-01" \
--data-urlencode "to=2026-02-28" \
--data-urlencode "action_family=outbound" \
--data-urlencode "action_key=outbound::partner:directory"
<form action="/api/demo" data-analytics-id="demo_request">
<button type="submit">Request a demo</button>
</form>

Query it with:

Terminal window
curl -sS -G "https://api.pomeloanalytics.com/v1/reports/actions" \
-H "Authorization: Bearer $POMELO_API_TOKEN" \
--data-urlencode "site_id=site_123" \
--data-urlencode "from=2026-02-01" \
--data-urlencode "to=2026-02-28" \
--data-urlencode "action_family=forms" \
--data-urlencode "action_key=forms::demo_request"
<section data-analytics-scope="hero">
<a href="/demo" data-analytics-id="primary">Request a demo</a>
</section>

Pomelo exposes this click publicly as action_key=instrumentation::hero/primary.

If you need to count a submit, tag the <form> itself. If you need to count a click before submission, tag the clickable control.

For outbound links, data-analytics-id is still recommended for stable CTA reporting. Without an explicit tag, Pomelo can still count the outbound click when you query action_family=outbound, and the response will still expose grouped outbound destinations through top_targets, but that is no longer the primary path for tagged event reporting.

When no data-analytics-label is set, the SDK detects a label automatically in this order:

  1. data-analytics-label attribute (el_label_src: "data")
  2. aria-label attribute (el_label_src: "aria")
  3. aria-labelledby resolved text (el_label_src: "aria")
  4. title attribute (el_label_src: "title")
  5. Visible text content for buttons, links, submit controls, and similar clickable elements — not free-form form inputs and not contentEditable (el_label_src: "text")
  6. value for <input type="submit"> or <input type="button"> only (el_label_src: "value")
  7. alt for images (el_label_src: "text")

Inside a <form>, only submit and button elements are eligible for text/value extraction. contentEditable elements are ignored.

Auto-detected labels are best-effort only. For stable analytics, prefer explicit attributes:

  • data-analytics-id
  • data-analytics-label

The script does not decide the profile on its own.

  • Strict keeps the bounded audience-measurement baseline.
  • In Strict, the simple-action subset remains available for stable IDs and bounded destinations/paths: ui.click, outbound.click, file.download, form.submit.
  • Extended unlocks richer collection such as acquisition parameters, multi-tenant context, and broader autocapture when that behavior is enabled for the site.

If a site is Strict, Extended-only events and fields are still filtered again server-side by ingest even if the client tries to send them.

That means UTM, full referrer values, auto-detected labels, error events, tenant enrichments, and rich custom events stay outside the default Strict envelope.

This simple subset must not be read as a general reopening of actions. It is a bounded aggregate action layer only, not a full product or marketing action intelligence surface.

data-autocapture-labels-only (default: false)

Section titled “data-autocapture-labels-only (default: false)”

This optional script attribute is a local restriction only. It cannot enable Extended collection on a Strict site.

When true:

  • ui.click only fires for elements with an explicit data-analytics-id
  • Clicks detected only via label auto-detection are suppressed
  • el_label and el_label_src are not emitted
  • el_role may still be emitted when available

Use this mode when you want stricter client-side control over which UI interactions are emitted.

Do not rely on snippet-level attributes such as data-autocapture-ui, data-autocapture-forms, data-autocapture-errors, data-capture-localhost, or data-allow-params as active sources of truth. The current authoritative behavior comes from the server-side site configuration.

FieldMax lengthOn PII detectionOn overflowCharset
el_id100Dropped entirelyDropped entirely[a-zA-Z0-9_\-.:/ ]
el_scope100Dropped entirelyDropped entirelySame as el_id
form_id100Dropped entirelyDropped entirelySame as el_id
el_label80Dropped entirelyTruncated to 80Any (PII-scanned)
page_title200Dropped entirelyTruncated to 200Any (PII-scanned)
error.msg200[redacted]Truncated to 200Any

PII patterns detected: email addresses, phone numbers, UUIDs, long numeric sequences (10+ consecutive digits), token-like strings (20+ alphanumeric characters).

Enable debug mode with either:

  • data-debug="true" on the script tag
  • ?pomelo_debug in the page URL

Console logs show [pomelo] debug information such as queued payloads, flush activity, and initialization details. A warning is shown if the page is not served over HTTPS.