> ## Documentation Index
> Fetch the complete documentation index at: https://docs.datalyr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Web SDK

> Track events and attribution in web browsers with the DATALYR Web SDK

The DATALYR Web SDK enables client-side event tracking, attribution capture, and identity resolution for websites and single-page applications.

## What It Does

**Browser Tracking:**

* Automatic pageview tracking
* Custom event tracking
* User identification and sessions
* Attribution data capture (UTM params, referrers)
* Device fingerprinting
* Cross-domain tracking
* Cookie management
* Container/tag manager integration

## Installation

### Option 1: npm Package (Recommended)

```bash theme={null}
npm install @datalyr/web
```

**Initialize:**

```javascript theme={null}
import datalyr from '@datalyr/web';

datalyr.init({
  workspaceId: 'abc123xyz'
});
```

The npm package is the recommended approach — it bundles into your own domain for better privacy, avoids ad blockers, and gives you full access to the SDK API including TypeScript support, plugins, and tree-shaking.

### Option 2: Script Tag

For sites without a build system, copy tracking script from **Settings → Tracking Script**:

```html theme={null}
<script defer src="https://track.datalyr.com/dl.js"
  data-workspace-id="abc123xyz">
</script>
```

Place in `<head>` tag before closing `</head>` on all pages.

<Tip>
  **Serve it first-party.** If you've set up a [tracking domain](/features/first-party-tracking), point the script at *your* host instead — `https://go.yourbrand.com/dl.js`. The SDK auto-derives its endpoint from the script's origin and sends events first-party: a durable, server-set visitor cookie that survives Safari/ITP, plus fewer events lost to ad-blockers. For the **npm package**, set `endpoint: 'https://go.yourbrand.com'` in `init()` to get the same first-party behavior.
</Tip>

## Basic Usage

### Track Events

```javascript theme={null}
// Track custom event
datalyr.track('button_click', {
  button_name: 'signup',
  page: 'homepage'
});

// Track with revenue
datalyr.track('purchase', {
  revenue: 99.99,
  currency: 'USD',
  product_id: 'prod_123'
});
```

### Track Pageviews

**Automatic (Default):**
Initial pageview tracked automatically on script load.

**Manual:**

```javascript theme={null}
// Track pageview manually
datalyr.page();

// With custom properties
datalyr.page({
  category: 'blog',
  author: 'John Doe'
});
```

**SPAs (Single-Page Apps):**
Automatic tracking for React Router, Vue Router, Next.js navigation via history API monitoring.

### Identify Users

```javascript theme={null}
// After user logs in
datalyr.identify('user_123', {
  email: 'john@example.com',
  name: 'John Doe',
  plan: 'pro'
});
```

Links anonymous visitor to known user for attribution.

<Note>
  The signature is `identify(userId, traits)` — pass the email as both the `userId` and a `traits.email`, e.g. `datalyr.identify('john@example.com', { email: 'john@example.com' })`. It is **not** `identify({ email })`. This is the deterministic web→app match key for [App Campaigns](/features/app-campaigns).
</Note>

### Auto-Identify (Email Capture)

Automatically capture the visitor's email — without writing an `identify()` call — from form/optin submits, same-origin XHR/fetch bodies, and (on Shopify) the logged-in customer. This is the lowest-friction way to light up deterministic web→app matching on App Campaigns landers. **Off by default.**

**Recommended — turn it on in the dashboard (no code):** enable Auto Identify in **Settings → Identity & Attribution**. It applies to the live SDK in \~5 minutes with no snippet change. See the [Identity Bridge](/features/identity-bridge).

**Script tag — one attribute:**

```html theme={null}
<script defer src="https://track.datalyr.com/dl.js"
  data-workspace-id="abc123xyz"
  data-auto-identify="true">
</script>
```

**Programmatic init:**

```javascript theme={null}
datalyr.init({ workspaceId: 'abc123xyz', autoIdentify: true });
```

When it captures an email it calls `identify()` for you (firing `$identify`).

<Note>
  Precedence is **built-in defaults ← dashboard ← explicit `init()`/attribute**. An explicit `autoIdentify` in code (or `data-auto-identify` on the tag) always wins over the dashboard toggle, so you can pin a per-environment value in code and still manage everything else from the dashboard.
</Note>

<Warning>
  `autoIdentify` captures from form submits and **same-origin** requests. If your optin POSTs to a third-party email tool on another domain, the XHR path won't see it — use an explicit `identify()` call instead. It also stores the captured email in the browser, so for **health or other redacted verticals do not enable it** — there is no automatic client-side redaction.
</Warning>

### Reset on Logout

```javascript theme={null}
// Clear user identity
datalyr.reset();
```

Creates new anonymous visitor ID.

## Configuration

### Initialization Options

```javascript theme={null}
datalyr.init({
  workspaceId: 'abc123xyz',

  // Optional settings
  debug: false,                    // Enable debug logs
  endpoint: 'https://ingest.datalyr.com',

  // Queue settings
  batchSize: 10,                   // Events per batch
  flushInterval: 5000,             // Flush every 5s
  flushAt: 10,                     // Auto-flush at 10 events

  // Session settings
  sessionTimeout: 1800000,         // 30 min timeout
  trackSessions: true,

  // Attribution settings
  attributionWindow: 2592000000,   // 30 days
  trackedParams: ['utm_source', 'utm_medium', 'utm_campaign', 'gclid', 'fbclid'],

  // Privacy settings
  respectDoNotTrack: false,
  respectGlobalPrivacyControl: true,
  privacyMode: 'standard',         // 'standard' or 'strict'

  // Auto-identify (email capture) — OFF by default
  autoIdentify: false,             // true = auto-capture email from forms / optins / Shopify
  autoIdentifyForms: true,         // capture from form submits (when autoIdentify on)
  autoIdentifyAPI: false,          // OFF by default — same-origin XHR/fetch scan can mis-identify (e.g. admin views); opt in explicitly
  autoIdentifyShopify: true,       // capture from Shopify /account.json

  // Cookie settings
  cookieDomain: 'auto',            // Auto-detect or '.example.com'
  cookieExpires: 365,              // Days
  secureCookie: 'auto',
  sameSite: 'Lax',

  // Tracking settings
  trackPageViews: true,            // Auto-track pageviews
  trackSPA: true,                  // Track SPA navigation
  enableFingerprinting: true,
  enablePerformanceTracking: true,

  // Container settings
  enableContainer: true            // Load container scripts
});
```

## Advanced Features

### Super Properties

Properties sent with every event:

```javascript theme={null}
// Set once, sent with all events
datalyr.setSuperProperties({
  app_version: '2.1.0',
  environment: 'production'
});

// Unset super property
datalyr.unsetSuperProperty('environment');
```

### Manual Attribution

```javascript theme={null}
// Set attribution manually
datalyr.setAttribution({
  utm_source: 'google',
  utm_medium: 'cpc',
  utm_campaign: 'summer_sale'
});

// Get current attribution
const attribution = datalyr.getAttribution();
```

### Journey Tracking

```javascript theme={null}
// Get customer journey (all touchpoints)
const journey = datalyr.getJourney();
// Returns array of attribution touchpoints
```

### Session Management

```javascript theme={null}
// Get current session ID
const sessionId = datalyr.getSessionId();

// Get session data
const session = datalyr.getSessionData();

// Start new session manually
datalyr.startNewSession();
```

### Identity Management

```javascript theme={null}
// Get anonymous ID
const anonId = datalyr.getAnonymousId();

// Get user ID (if identified)
const userId = datalyr.getUserId();

// Get distinct ID (userId or anonId)
const distinctId = datalyr.getDistinctId();

// Alias user (connect IDs)
datalyr.alias('user_123', 'previous_id');
```

### Group Tracking

```javascript theme={null}
// Associate user with account/organization
datalyr.group('company_456', {
  name: 'Acme Corp',
  plan: 'enterprise'
});
```

### Screen Tracking (SPAs)

```javascript theme={null}
// Track screen view
datalyr.screen('Dashboard', {
  section: 'analytics'
});
```

### Opt-Out/Consent

```javascript theme={null}
// Opt user out of tracking
datalyr.optOut();

// Opt user back in
datalyr.optIn();

// Check opt-out status
const isOptedOut = datalyr.isOptedOut();

// Set consent preferences
datalyr.setConsent({
  analytics: true,
  advertising: false
});
```

### Manual Flush

```javascript theme={null}
// Flush events immediately
await datalyr.flush();
```

### Container Scripts

```javascript theme={null}
// Load custom container script by ID
datalyr.loadScript('script_abc123');

// Get loaded scripts
const loadedScripts = datalyr.getLoadedScripts();
```

### Web-to-App Attribution

Track app download clicks for enhanced app campaigns:

```javascript theme={null}
// Track iOS app download
datalyr.trackAppDownloadClick({
  targetPlatform: 'ios',
  appStoreUrl: 'https://apps.apple.com/app/idXXXXXXXXXX'
});

// Track Android app download
datalyr.trackAppDownloadClick({
  targetPlatform: 'android',
  appStoreUrl: 'https://play.google.com/store/apps/details?id=com.example.app'
});
```

This method captures full attribution data, flushes the event queue, and redirects the user to the app store. For Android, it encodes referrer parameters into the Play Store URL for deterministic attribution.

[Learn more about App Campaigns](/features/app-campaigns)

## Privacy Features

### Cookie Management

**Cookies Created:**

* `__dl_visitor_id`: Visitor identifier (365 days)
* `__dl_session_id`: Session identifier (30 min)
* `__dl_attribution`: Attribution data (30 days)
* `__dl_opt_out`: Opt-out status (permanent)

**Cookie Domain:**

```javascript theme={null}
datalyr.init({
  cookieDomain: '.example.com'  // Share across subdomains
});
```

### Do Not Track

```javascript theme={null}
datalyr.init({
  respectDoNotTrack: true  // Respect browser DNT setting
});
```

### Global Privacy Control

```javascript theme={null}
datalyr.init({
  respectGlobalPrivacyControl: true  // Respect GPC signal
});
```

### Fingerprinting

```javascript theme={null}
datalyr.init({
  enableFingerprinting: false  // Disable device fingerprinting
});
```

## Performance Tracking

**Automatic Performance Metrics:**

* Page load time
* DOM ready time
* First byte time
* DNS, TCP, request times

**Disable:**

```javascript theme={null}
datalyr.init({
  enablePerformanceTracking: false
});
```

## Cross-Domain Tracking

**Same Root Domain (Subdomains):**
Enable in Settings → Advanced → Cross-Domain Tracking → Include Subdomains.

Cookies set on `.example.com` work across `www.example.com`, `app.example.com`, `blog.example.com`.

**Different Domains:**
Enable in Settings → Advanced → Cross-Domain Tracking and add domains to whitelist.

Links automatically include `_dl_visitor` parameter to maintain identity.

## Debugging

**Enable Debug Mode:**

```javascript theme={null}
datalyr.init({
  debug: true
});
```

**Check Status:**

```javascript theme={null}
// View SDK errors
const errors = datalyr.getErrors();

// View network status
const status = datalyr.getNetworkStatus();
```

**Browser Console:**
All events logged to console when `debug: true`.

## TypeScript Support

Full TypeScript definitions included:

```typescript theme={null}
import datalyr, {
  DatalyrConfig,
  EventProperties,
  UserTraits
} from '@datalyr/web';

const config: DatalyrConfig = {
  workspaceId: 'abc123xyz',
  debug: true
};

datalyr.init(config);

const properties: EventProperties = {
  revenue: 99.99,
  currency: 'USD'
};

datalyr.track('purchase', properties);
```

## Framework Integration

### React

```javascript theme={null}
import { useEffect } from 'react';
import datalyr from '@datalyr/web';

function App() {
  useEffect(() => {
    datalyr.init({ workspaceId: 'abc123xyz' });
  }, []);

  const handleClick = () => {
    datalyr.track('button_click');
  };

  return <button onClick={handleClick}>Click Me</button>;
}
```

### Vue

```javascript theme={null}
import datalyr from '@datalyr/web';

export default {
  mounted() {
    datalyr.init({ workspaceId: 'abc123xyz' });
  },
  methods: {
    handleClick() {
      datalyr.track('button_click');
    }
  }
}
```

### Next.js

```javascript theme={null}
// pages/_app.js
import { useEffect } from 'react';
import datalyr from '@datalyr/web';

function MyApp({ Component, pageProps }) {
  useEffect(() => {
    datalyr.init({
      workspaceId: 'abc123xyz',
      trackSPA: true
    });
  }, []);

  return <Component {...pageProps} />;
}
```

## Common Use Cases

**E-commerce Tracking:**

```javascript theme={null}
// Product view
datalyr.track('product_view', {
  product_id: 'prod_123',
  name: 'Premium Widget',
  price: 99.99
});

// Add to cart
datalyr.track('add_to_cart', {
  product_id: 'prod_123',
  quantity: 2
});

// Purchase
datalyr.track('purchase', {
  order_id: 'order_456',
  revenue: 199.98,
  currency: 'USD',
  products: ['prod_123']
});
```

**SaaS Tracking:**

```javascript theme={null}
// Signup
datalyr.track('signup', {
  plan: 'pro',
  trial: true
});
datalyr.identify('user_123', {
  email: 'user@example.com'
});

// Feature usage
datalyr.track('feature_used', {
  feature: 'export_csv',
  count: 1
});

// Upgrade
datalyr.track('plan_upgrade', {
  from: 'pro',
  to: 'enterprise'
});
```

**Lead Generation:**

```javascript theme={null}
// Form view
datalyr.track('form_view', {
  form_id: 'contact_form'
});

// Form submission
datalyr.track('form_submit', {
  form_id: 'contact_form',
  email: 'lead@example.com'
});
datalyr.identify('lead_123', {
  email: 'lead@example.com',
  source: 'contact_form'
});
```

## Troubleshooting

**Events Not Appearing:**

* Check workspace ID matches Settings
* Open browser console and check for errors
* Enable `debug: true` to see event logs
* Check Event Stream for recent events
* Verify script loads (Network tab)

**Attribution Not Captured:**

* Check URL has UTM parameters
* Ensure `trackSessions: true`
* Verify cookies not blocked
* Check `trackedParams` includes your params

**Cross-Domain Not Working:**

* Enable in Settings → Advanced
* Add all domains to whitelist
* Check links include `_dl_visitor` param
* Verify cookie domain settings

## Browser Support

**Supported:**

* Chrome 60+
* Firefox 55+
* Safari 12+
* Edge 79+
* Mobile browsers (iOS Safari, Chrome Mobile)

**Graceful Degradation:**
SDK fails silently in unsupported browsers without breaking site functionality.

## Next Steps

<CardGroup cols={2}>
  <Card title="Server SDK" icon="server" href="/sdks/server">
    Backend tracking guide
  </Card>

  <Card title="Mobile SDKs" icon="mobile" href="/sdks/mobile">
    iOS & React Native guide
  </Card>

  <Card title="Advanced Topics" icon="code" href="/sdks/advanced">
    Identity, batching, plugins
  </Card>

  <Card title="Event Stream" icon="water" href="/features/event-stream">
    Verify tracked events
  </Card>
</CardGroup>
