Skip to content

Web SDK ​

Set up Linkrunner's beta Web Attribution SDK for page views, users, events, and traffic-source attribution

The Linkrunner Web SDK tracks page views, known users, custom events, and the traffic sources that brought visitors to your website.

Web Attribution is currently in beta. To request access, email support@linkrunner.io with your project name and website domain. We will enable Web Attribution and send you a Web SDK token.

The SDK automatically captures:

  • Page views, including single-page app navigation
  • First-touch and last-touch UTM attribution
  • Ad click IDs such as gclid, fbclid, and ttclid
  • Paid, organic, social, AI search, referral, and direct traffic
  • Browser, device, geography, and performance data

1. Add the SDK ​

We recommend loading the browser SDK from the Linkrunner CDN. This lets Linkrunner ship fixes and updates without requiring you to change or redeploy your integration.

The direct script tag and the Next.js helper both load https://cdn.linkrunner.io/web/v1/lr.js by default. The npm package provides the typed Next.js component and event methods, while the browser SDK still stays current through the CDN.

Add this script before the closing </head> tag. Replace YOUR_WEB_SDK_TOKEN with the token provided by Linkrunner.

html
<script
  src="https://cdn.linkrunner.io/web/v1/lr.js"
  data-token="YOUR_WEB_SDK_TOKEN"
  defer
></script>

The SDK tracks the first page view when it loads. Single-page app navigation is tracked by default.

2. Identify users and track events ​

Call identify after a user signs in or when you otherwise know their identity. Use a stable internal user ID rather than an email address or phone number.

js
import { lr } from '@linkrunner/web'

lr.identify(String(user.id))

With the script tag, use the global object:

js
window.lr.identify(String(user.id))

The SDK saves this ID in localStorage and includes it as user_id on later events.

Track a custom event with track:

js
lr.track('purchase', {
  amount: 49.99,
  currency: 'USD',
})

To show a signed-up user's details in the Web Events dashboard, identify the user and then send a signup event:

js
lr.identify(String(user.id))

lr.track('signup', {
  name: user.name,
  email: user.email,
  phone: user.phone,
})

Only send personal data when you have permission to do so. Calling identify does not add the user ID to events that were already captured.

Calls made before the SDK finishes loading are queued and replayed after initialization.

Function Placement Guide ​

The Web SDK initializes when the script loads. It uses identify for the customer user ID and track('signup', ...) for signup, rather than the mobile SDK method names. It captures incoming URL attribution automatically and does not expose handleDeeplink.

FunctionRequirementWhere to PlaceWhen to Call
SDK script / LinkrunnerScriptRequiredHTML head, root layout, or _app.tsxOnce when your website loads
lr.track('signup', ...)RequiredSignup or login flow, after identifyWhen you identify a signed-up user
lr.identifyRequiredAuthentication logicWhen you know your user's stable ID
lr.trackOptionalEvent handlers throughout your websiteWhen you record other user actions

3. Verify the integration ​

Set data-debug="true" while testing:

html
<script
  src="https://cdn.linkrunner.io/web/v1/lr.js"
  data-token="YOUR_WEB_SDK_TOKEN"
  data-debug="true"
  defer
></script>

Then open your browser's developer tools:

  1. In Console, confirm that messages start with [Linkrunner] and include Initialized.
  2. In Network, confirm that page views and events send a POST request to /web/ingest.
  3. Trigger a test event and confirm the console reports Sent via fetch.

Debug logging turns on automatically on localhost, 127.0.0.1, and [::1]. Remove data-debug="true" after testing.

Configuration ​

Script tag attributes ​

AttributeRequiredDescriptionDefault
data-tokenYesYour Web SDK tokenNone
data-domainNoYour first-party collection hostname, such as lr.example.comNone
data-endpointNoA full URL or same-origin path for a proxy you operateNone
data-spaNoSet to "false" to disable automatic SPA page viewstrue
data-debugNoSet to "true" or "false" to control console loggingOn for local development

You can also set the same options before the script loads:

html
<script>
  window.LinkrunnerConfig = {
    token: 'YOUR_WEB_SDK_TOKEN',
    spa: true,
    debug: false,
  }
</script>
<script src="https://cdn.linkrunner.io/web/v1/lr.js" defer></script>

Without data-domain or data-endpoint, events go to https://api.linkrunner.io/web/ingest.

First-party collection ​

Some ad blockers stop requests to analytics domains. First-party collection sends events through your own domain instead.

Proxy through your website ​

This is the most reliable option because both the SDK and event endpoint use paths on your website. For Next.js, add two rewrites:

js
// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/lr/lr.js',
        destination: 'https://cdn.linkrunner.io/web/v1/lr.js',
      },
      {
        source: '/lr/ingest',
        destination: 'https://api.linkrunner.io/web/ingest',
      },
    ]
  },
}

Point LinkrunnerScript at those routes:

tsx
<LinkrunnerScript
  token="YOUR_WEB_SDK_TOKEN"
  scriptSrc="/lr/lr.js"
  endpoint="/lr/ingest"
/>

For a plain script tag:

html
<script
  src="/lr/lr.js"
  data-token="YOUR_WEB_SDK_TOKEN"
  data-endpoint="/lr/ingest"
  defer
></script>

Your proxy must preserve the visitor's IP address. Forward X-Forwarded-For with the visitor's address first, or set X-Linkrunner-Visitor-IP explicitly. If the proxy drops it, geographic data will identify your proxy instead of the visitor.

Point a subdomain at Linkrunner ​

Use this option when you cannot add proxy routes to your website.

Register the subdomain

In the Linkrunner dashboard, open Settings → Manage Domains and add the collection subdomain you want to use, such as lr.example.com.

Add the DNS record

Add a CNAME record with your DNS provider:

text
lr.example.com.  CNAME  api.linkrunner.io.

Linkrunner issues the TLS certificate on the first request for a registered subdomain.

Configure the SDK

Add data-domain to the script tag:

html
<script
  src="https://cdn.linkrunner.io/web/v1/lr.js"
  data-token="YOUR_WEB_SDK_TOKEN"
  data-domain="lr.example.com"
  defer
></script>

For Next.js, use the domain prop:

tsx
<LinkrunnerScript token="YOUR_WEB_SDK_TOKEN" domain="lr.example.com" />

Verify the endpoint

Run this request before relying on the subdomain:

bash
curl -i -X OPTIONS \
  -H 'Origin: https://example.com' \
  -H 'Access-Control-Request-Method: POST' \
  https://lr.example.com/web/ingest

Expect a 204 response with an access-control-allow-origin header. Then confirm in your browser's Network tab that event requests go to https://lr.example.com/web/ingest.

Set data-domain to a hostname, not a URL. The SDK accepts a scheme or trailing slash, but it always normalizes the value to https://HOST/web/ingest. Use data-endpoint only when you control the full proxy path.

If each event creates one request to your subdomain and another to api.linkrunner.io, the first-party endpoint is failing and the SDK is using its fallback. Check the CNAME, domain registration, and any firewall or authentication rules in front of the subdomain.

Attribution storage ​

DataStorageLifetime
First-touch UTMs and click IDslocalStorageUntil browser storage is cleared
Last-touch click IDslocalStorage90 days
Last-touch UTMssessionStorage and localStorage24 hours from the campaign click
Visitor ID and user IDlocalStorageUntil browser storage is cleared
Session ID and page countsessionStorageCurrent tab session

The 24-hour localStorage copy preserves last-touch UTMs when a payment gateway or 3D Secure flow returns the visitor in a new tab.

Troubleshooting ​

The SDK says the token is invalid

Confirm that you are using the Web SDK token provided by Linkrunner. Mobile SDK project tokens do not work with the Web SDK. If you need a token, contact support@linkrunner.io.

Page views are duplicated

Load the SDK once. In Next.js, put LinkrunnerScript in the root layout or _app.tsx, not on individual pages. The SDK already tracks SPA navigation by default.

Events are blocked in the browser

Use first-party collection. A same-origin proxy is the strongest option. A CNAME may still be detected by browsers that inspect DNS records.

A payment or other trusted event can be sent from the browser

Do not trust client-side events for payments, entitlements, or other sensitive state changes. Send those events from your backend with the Event Capture API or Revenue Tracking API.

More resources ​

Need help or beta access? Contact support@linkrunner.io