JavaScript

Introduction

The Lytics JavaScript Tag (JS Tag) is the primary SDK for collecting behavioral data from your website visitors and delivering real-time personalization. It handles:

  • Behavioral tracking — page views, clicks, form submissions, and custom events that build user profiles with content affinities and behavioral scores
  • Identity resolution — associating anonymous visitors with known user profiles across sessions and devices
  • Profile delivery — surfacing audience membership and user attributes to the browser for personalization
  • Integration handoff — forwarding profile data to web-based integrations like Google Analytics, Facebook Ads, and others

This guide walks you through installation, tagging strategy, common implementation patterns, and troubleshooting — everything you need to get the most out of the Lytics platform on your web properties.

Quick Start

1. Install the Tag

Copy the JS Tag snippet from the Lytics app installation page and paste it into your site's <head> tag. It looks like this:

<script type="text/javascript">
  !function(){"use strict";var o=window.jstag||(window.jstag={}),r=[];function n(e){o[e]=function(){for(var n=arguments.length,t=new Array(n),i=0;i<n;i++)t[i]=arguments[i];r.push([e,t])}}n("send"),n("mock"),n("identify"),n("pageView"),n("unblock"),n("getid"),n("setid"),n("loadEntity"),n("getEntity"),n("on"),n("once"),n("call");o.loadScript=function(n,t,i){var e=document.createElement("script");e.async=!0,e.src=n,e.onload=t,e.onerror=i;var o=document.getElementsByTagName("script")[0];o.parentNode.insertBefore(e,o)},o.init=function n(t){o.config=t,t.callback?o.loadScript(t.src,function(){var n=window.jstag;for(var e in o.config=t,o)n[e]||(n[e]=o[e]);r.forEach(function(n){n[0]in window.jstag&&window.jstag[n[0]].apply(window.jstag,n[1])}),r=[],"init"in n&&n.init(t),t.callback(n)}):o.loadScript(t.src)},o.init({
    src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
  })}();
</script>

Replace YOUR_ACCOUNT_ID with your Lytics account ID (found in Account Settings).

2. Verify Installation

Open your browser's developer console and run:

jstag.config.version;

If a version number is returned (e.g., 3.x.x), the tag is installed and collecting data. You can also use the automated verification checker in the Lytics app installation page.

3. Send Your First Event

In the browser console (or in your site code), send a test event:

jstag.send({ event: "test_event" });

4. Verify Data in Lytics

Open the Network tab in developer tools and filter for lytics.io. You should see requests to the /c collection endpoint. Check the Payload section to confirm your data was sent.

Then visit the stream/pipeline section in the Lytics app to verify the event arrived.

Installation

Standard Script Tag

The recommended approach is to paste the JS Tag snippet directly in your site's <head> section. This ensures the tag loads early and captures all page views. Get your snippet from the installation page in the Lytics app.

Google Tag Manager

  1. Log into GTM.
  2. Click New Tag > Tag Configuration.
  3. Under Custom, select Custom HTML.
  4. Paste the Lytics JS Tag snippet.
  5. Name it Lytics JavaScript Tag.
  6. In Triggering, select All Pages.
  7. Click Save, then Submit to publish.
  8. Visit your site and click through a few pages to generate traffic.
  9. Check the Tag Installation Status on the installation page.

Other Tag Managers

Lytics can be installed through virtually any tag manager. The process is generally the same: create a custom HTML tag, paste the Lytics snippet, trigger on all pages, and publish.

Subresource Integrity (SRI)

For environments that require SRI, see the SRI documentation.

Self-Hosting the Tag

While not recommended (it means you miss automatic updates and may void SLA agreements), it is possible to host the JS Tag from your own infrastructure. The trade-offs:

Benefits:

  • Compliance with strict security requirements

Drawbacks:

  • No automatic feature updates or bug fixes
  • Client-side integrations require manual configuration
  • Account settings no longer update dynamically
  • You are responsible for caching and scalability

If required, follow these steps:

  1. Navigate to the src URL from your tag snippet (e.g., //c.lytics.io/api/tag/YOUR_ID/latest.min.js) in a browser and save the file.
  2. Host the file on your infrastructure.
  3. Update the src in your jstag.init config:
jstag.init({
  src: '//yourcompany.com/assets/lytics.latest.min.js'
});

Configuration

Version 3 is configured out-of-the-box for most use cases. Additional options are available for custom or advanced scenarios.

Configuration Options

KeyTypeRequiredDefaultDescription
srcstringYesURL to load the tag from (provided by Lytics)
urlstringYes//c.lytics.ioCollection endpoint URL. Do not change this.
cidstringYesAccount ID (auto-set from src when using the generated snippet)
loadidbooleanNofalseEnable third-party cookies for cross-domain identity resolution
streamstringNo"default"Data stream name for collected events
sessecsintegerNo1800Session timeout in seconds (30 minutes)
qsargsstring[]No[]Query parameters to always collect from the URL
serializerstringNo"default""default" or "legacy" (for v2 migration only)
cookiesobjectNoCookie domain config, e.g., { domain: ".site.com" }
entityobjectNoCustom identifier config (byFieldKey, byFieldValue)
pageAnalysisobjectNoControl automatic page data collection
pathforaobjectNoPersonalization widget configuration

Configuration Details

  • url — The generated URL should never be changed as it will prevent your data from being sent to Lytics.
  • cid — Automatically included when using the generated tag snippet. Do not alter.
  • loadid — Enables Lytics to use a third-party cookie if available, pulling cross-domain behavior into a single unified user profile. Useful when you own multiple domains.
  • stream — When collecting data across multiple domains, it is common to use a custom stream per domain. Custom streams require corresponding LQL to surface the collected data as user fields. See Tagging Strategy below.
  • serializer — Only use "legacy" if migrating from v2 with deeply nested data. Otherwise, leave as "default".
  • cookies — Sets the cookie domain for the Lytics cookie. Useful for sites with many subdomains to ensure consistent tracking:
    { cookies: { domain: ".yoursite.com" } }
  • entity — Use a custom identifier instead of the Lytics cookie. See Identity & User Identification.
  • pageAnalysis — Controls automatic page data extraction:
    { pageAnalysis: { collectQueryParams: true, dataLayerPull: { disabled: false } } }

Example Configuration

jstag.init({
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
  loadid: true,
  stream: 'web_main',
  sessecs: 1800,
  qsargs: ['utm_source', 'utm_medium', 'utm_campaign'],
  cookies: { domain: '.yoursite.com' }
});

Tagging Strategy & Best Practices

What to Tag

A good tagging implementation captures four categories of data:

CategoryPurposeExamples
Page viewsContent consumption, browsing behaviorAutomatic (or manual for SPAs)
Identity eventsLink anonymous visitors to known usersLogin, registration, form submission with email
Behavioral eventsActions that indicate intent or engagementSearch, video play, download, add-to-cart
Conversion eventsBusiness outcomesPurchase, subscription, form completion

You do not need to tag everything. Focus on events that will drive your use cases — audience building, personalization, and attribution.

Event Naming Conventions

Use consistent, lowercase, snake_case names for events and fields:

// Good
jstag.send({ event: "product_viewed", product_id: "SKU-123" });
jstag.send({ event: "form_submitted", form_name: "newsletter_signup" });
jstag.send({ event: "purchase_completed", order_value: 49.99 });

// Avoid
jstag.send({ event: "Product Viewed" });   // spaces, mixed case
jstag.send({ event: "formSubmitted" });     // camelCase
jstag.send({ event: "click" });             // too generic

Payload Structure

Keep payloads flat. Lytics works best with flat key-value pairs:

// Good — flat structure
jstag.send({
  event: "purchase_completed",
  order_id: "ORD-456",
  order_value: 129.99,
  currency: "USD",
  product_category: "electronics"
});

// Avoid — deeply nested objects
jstag.send({
  event: "purchase_completed",
  order: {
    id: "ORD-456",
    total: { value: 129.99, currency: "USD" }
  }
});

When to Use Custom Streams

The default stream ("default") works for most single-site implementations. Use custom streams when:

  • Multiple domains — one stream per domain (e.g., web_main, web_blog, web_support)
  • Different data schemas — events with very different field structures
  • Separate LQL processing — you need different field mappings per data source

Custom streams require corresponding LQL statements to map raw fields into user profile fields. Consult your Lytics account team when setting up custom streams.

How Data Flows

Understanding the data pipeline helps you tag effectively:

Browser (jstag.send)
    → /c endpoint (collection)
        → Data Stream (e.g., "default")
            → LQL Processing (field mapping, identity resolution)
                → User Profile (audiences, scores, affinities)
                    → /personalize endpoint
                        → Browser (entityReady callback)

Every jstag.send() call sends data to the /c collection endpoint, which routes it to the configured stream. LQL statements on that stream define how raw fields map to user profile fields, which identity fields to use for profile merging, and how to aggregate values over time. The enriched profile is then available back in the browser through the /personalize endpoint.

Data Collection

Automatically Collected Data

The JS Tag automatically collects the following fields with every event:

FieldExampleDescription
_epvEvent type (pv = page view)
_refwww.google.comReferral domain
_tz-7Time zone offset from UTC
_ulen-USBrowser language
_sz2560x1440Display size
_ts1504306728695Timestamp (milliseconds since epoch)
_nmobtNot mobile (t = desktop)
_devicedesktopDevice type
urlwww.yoursite.com/pagePage URL
_uid74481.3222228897Lytics cookie ID
_v3.0.2JS Tag version

You do not need to send these manually — they are included automatically.

Page Views

A page view is captured automatically each time the browser fully loads a new URL. For SPAs or when you need to manually trigger a page view:

jstag.pageView();

Custom Events

Use jstag.send() to collect any custom data. The method accepts a JavaScript object with any key-value pairs:

jstag.send({
  event: "button_clicked",
  button_name: "hero_cta",
  page_section: "homepage"
});

Advanced: Stream, Payload, and Callback

All collection methods accept three optional parameters:

jstag.send(STREAM, PAYLOAD, CALLBACK);
jstag.pageView(STREAM, PAYLOAD, CALLBACK);
ParameterTypeDescription
STREAMstringTarget stream name (overrides config default)
PAYLOADobjectThe data to send
CALLBACKfunctionCalled when the collect request completes
// Send to a specific stream with a callback
jstag.send('checkout_events', { event: "cart_updated", item_count: 3 }, function(response) {
  console.log("Event sent:", response);
});

Identity & User Identification

How Anonymous Tracking Works

On first visit, the JS Tag generates a unique _uid and stores it as a first-party cookie (seerid). This ID is included in every event, allowing Lytics to link all of a visitor's activity into a single anonymous profile — even across sessions.

Identifying Known Users

When a visitor provides identifying information (email, user ID, etc.), send it via jstag.send() to link the anonymous profile to a known identity:

// On login or form submission
jstag.send({
  email: "[email protected]",
  userid: "USR-12345",
  first_name: "Jane",
  last_name: "Doe"
});

This merges the anonymous cookie-based profile with any existing profile for that email or user ID. Send identity data at every opportunity — login, registration, form submission, email click-through — to maximize profile resolution.

Custom Entity Identifiers

By default, the JS Tag uses the _uid cookie to look up the visitor's profile. If you have authenticated users and want to use a stronger identifier:

// Get authenticated user from your auth system
var user = getAuthenticatedUser();

var config = {
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};

// Use a custom identifier for logged-in users
if (user) {
  config.entity = {
    byFieldKey: 'user_id',        // The Lytics profile field name
    byFieldValue: user.id          // The value from your auth system
  };
}

jstag.init(config);

When entity is configured, the /personalize endpoint will look up the visitor by the specified field instead of the cookie, returning a richer profile for known users.

Example: Email as Identifier

For sites where email is the primary known identifier (e.g., after a form submission or login):

var user = getAuthenticatedUser();

var config = {
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};

if (user && user.email) {
  config.entity = {
    byFieldKey: 'email',
    byFieldValue: user.email
  };
}

jstag.init(config);

Example: CRM Contact ID

If your users are managed in a CRM like Salesforce or HubSpot, use the CRM's contact ID to ensure profile consistency across systems:

var crmUser = getCRMContact();

var config = {
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};

if (crmUser && crmUser.contactId) {
  config.entity = {
    byFieldKey: 'salesforce_contact_id',
    byFieldValue: crmUser.contactId
  };
}

jstag.init(config);

Example: Internal Customer UUID

For platforms with their own customer database, use your internal UUID:

var customer = getCustomer();

var config = {
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};

if (customer && customer.uuid) {
  config.entity = {
    byFieldKey: 'customer_uuid',
    byFieldValue: customer.uuid
  };
}

jstag.init(config);

Example: Strongest Available Identifier with Fallback

In practice, you may have multiple identifiers available depending on the user's authentication state. Use the strongest one available:

var user = getAuthenticatedUser();

var config = {
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};

if (user && user.id) {
  // Strongest: authenticated user ID
  config.entity = {
    byFieldKey: 'user_id',
    byFieldValue: user.id
  };
} else if (user && user.email) {
  // Fallback: email from a previous form submission or cookie
  config.entity = {
    byFieldKey: 'email',
    byFieldValue: user.email
  };
}
// If neither is available, the default _uid cookie is used automatically

jstag.init(config);

Example: Server-Rendered Identifier

When your backend (CMS, application server, etc.) knows the current user, inject the identifier directly into the page template. This avoids a client-side auth lookup and ensures the identifier is available immediately when the tag loads.

PHP / WordPress:

<script type="text/javascript">
  // ... jstag snippet ...
  var config = {
    src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
  };

  <?php if (is_user_logged_in()): ?>
  var currentUser = <?php echo json_encode([
    'id' => get_current_user_id(),
    'email' => wp_get_current_user()->user_email
  ]); ?>;

  config.entity = {
    byFieldKey: 'user_id',
    byFieldValue: String(currentUser.id)
  };
  <?php endif; ?>

  jstag.init(config);
</script>

Django / Jinja2:

<script type="text/javascript">
  // ... jstag snippet ...
  var config = {
    src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
  };

  {% if user.is_authenticated %}
  config.entity = {
    byFieldKey: 'user_id',
    byFieldValue: '{{ user.pk }}'
  };
  {% endif %}

  jstag.init(config);
</script>

Ruby on Rails (ERB):

<script type="text/javascript">
  // ... jstag snippet ...
  var config = {
    src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
  };

  <% if current_user %>
  config.entity = {
    byFieldKey: 'user_id',
    byFieldValue: '<%= current_user.id %>'
  };
  <% end %>

  jstag.init(config);
</script>

Cross-Domain Tracking

If you own multiple domains and want to unify visitor profiles across them, enable loadid:

jstag.init({
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
  loadid: true
});

This uses a third-party cookie (when available) to resolve the same visitor across your domains.

Accessing the Anonymous ID

// Get the current visitor's _uid (async)
jstag.getid(function(id) {
  console.log("Visitor ID:", id);
});

// Override the _uid (advanced — use with caution)
jstag.setid('custom_id_value');
Manipulating the _uid is an advanced feature and can significantly impact how your profiles are compiled. Use at your own risk.

Common Tagging Patterns

User Login / Registration

Send identity data whenever a user authenticates. This is the most important tagging event for linking anonymous and known profiles.

// On successful login
jstag.send({
  event: "login",
  email: user.email,
  userid: user.id,
  first_name: user.firstName,
  last_name: user.lastName
});

// On registration
jstag.send({
  event: "registration",
  email: user.email,
  userid: user.id,
  signup_source: "website",
  plan: "free"
});

Form Submissions

Capture lead data when users submit forms:

// Newsletter signup
document.getElementById('newsletter-form').addEventListener('submit', function(e) {
  var email = document.getElementById('email-input').value;
  jstag.send({
    event: "newsletter_signup",
    email: email,
    form_name: "footer_newsletter",
    page_url: window.location.pathname
  });
});

// Contact form
jstag.send({
  event: "contact_form_submitted",
  email: formData.email,
  name: formData.name,
  company: formData.company,
  inquiry_type: formData.subject
});

E-Commerce

Product Views

jstag.send({
  event: "product_viewed",
  product_id: "SKU-789",
  product_name: "Running Shoes",
  product_category: "footwear",
  product_price: 89.99
});

Add to Cart

jstag.send({
  event: "add_to_cart",
  product_id: "SKU-789",
  product_name: "Running Shoes",
  quantity: 1,
  cart_value: 89.99
});

Purchase / Conversion

jstag.send({
  event: "purchase_completed",
  order_id: "ORD-456",
  order_value: 129.99,
  currency: "USD",
  item_count: 2,
  payment_method: "credit_card"
});

Content Engagement

Search

jstag.send({
  event: "search",
  search_query: document.getElementById('search-input').value,
  results_count: resultCount
});

Video Play

jstag.send({
  event: "video_played",
  video_id: "VID-001",
  video_title: "Product Demo",
  video_duration: 180
});

File Download

jstag.send({
  event: "file_downloaded",
  file_name: "whitepaper-2024.pdf",
  file_type: "pdf",
  content_category: "resources"
});

Campaign & Attribution Data

Capture UTM parameters and campaign data using qsargs in your configuration:

jstag.init({
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
  qsargs: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']
});

This automatically captures UTM parameters from the URL on every page view without any additional jstag.send() calls.

Declarative Tracking with lx-* Attributes

The JS Tag includes a plugin that lets you track user interactions directly in your HTML markup — no JavaScript required. Add lx-* attributes to any element and the tag will automatically listen for DOM events and send the data to Lytics.

Enabling the Plugin

The lx plugin is disabled by default. Enable it in your jstag.init configuration:

jstag.init({
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
  lx: {
    disabled: false
  }
});

Core Attributes

AttributeDescription
lx-triggerThe DOM event that triggers data collection (e.g., click, change, submit)
lx-sendQuery-string style payload (e.g., event=signup&plan=free)
lx-send-*Individual payload fields as separate attributes (e.g., lx-send-event="signup")
lx-streamRoute the event to a specific stream (defaults to "default")

All attributes also work with the data- prefix (e.g., data-lx-trigger, data-lx-send) for HTML5 validity.

Supported Triggers

The following DOM events can be used as lx-trigger values:

click, dblclick, change, input, focusin, focusout, keydown, keypress, mousedown, mouseout, mouseover, mouseup, touchstart, touchend, touchcancel, submit

Examples

Button Click

<button
  lx-trigger="click"
  lx-send="event=cta_clicked&button_name=hero_signup"
>
  Sign Up Now
</button>

This sends { "event": "cta_clicked", "button_name": "hero_signup" } when the button is clicked.

Using Individual Send Attributes

Instead of a query string, you can use lx-send-* attributes for each field:

<button
  lx-trigger="click"
  lx-send-event="cta_clicked"
  lx-send-button_name="hero_signup"
>
  Sign Up Now
</button>

This sends the same payload as the query-string example above.

Routing to a Custom Stream

<button
  lx-trigger="click"
  lx-send="event=download&file=whitepaper.pdf"
  lx-stream="content_engagement"
>
  Download Whitepaper
</button>

Form Submission

When lx-trigger="submit" is set on a <form>, the plugin automatically collects all form field values as the payload:

<form lx-trigger="submit">
  <input name="email" type="email" placeholder="[email protected]" />
  <input name="signup_source" type="hidden" value="footer_newsletter" />
  <button type="submit">Subscribe</button>
</form>

When submitted, this sends { "email": "[email protected]", "signup_source": "footer_newsletter" }. The plugin calls preventDefault() on the submit event, so handle any additional form submission logic (like redirecting or showing a confirmation) separately.

Tracking Input Changes

<select lx-trigger="change" lx-send-event="filter_changed" lx-send-filter_name="category">
  <option value="all">All</option>
  <option value="electronics">Electronics</option>
  <option value="clothing">Clothing</option>
</select>

Configuration Options

KeyTypeDefaultDescription
lx.disabledbooleantrueEnable/disable the plugin
lx.prefixstring"lx"Attribute prefix (change to use a different prefix)
lx.targetElementdocument.bodyContainer element for event delegation
lx.streamstring"default"Default stream when lx-stream is not specified
lx.triggersstring[](see above)List of DOM events to listen for

Notes

  • Keys in lx-send are case-sensitive: lx-send="Foo=bar&foo=baz" sends both Foo and foo as separate fields.
  • Hyphens in lx-send-* attribute names are converted to dots in the payload (e.g., lx-send-user-name="Jane" sends { "user.name": "Jane" }).
  • The plugin uses event delegation on the target container, so elements added dynamically to the DOM are tracked automatically.
  • Event listeners are cleaned up automatically when the JS Tag is torn down.

Single Page Apps (SPA)

SPAs require special handling because the browser does not fully reload between route changes. Version 3 of the JS Tag is built with SPAs in mind.

Route Change Handling

On each route change, you need to:

  1. Track a page view for the new route.
  2. Optionally reload the visitor profile and re-evaluate campaigns.
// Call this on every route change in your SPA
function onRouteChange() {
  // Track the new page view
  jstag.pageView();

  // Re-fetch the profile and trigger configured campaigns
  jstag.loadEntity(function(profile) {
    console.log("Profile refreshed:", profile.data);
  });
}

React Example

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function LyticsPageTracker() {
  const location = useLocation();

  useEffect(() => {
    window.jstag.pageView();
    window.jstag.loadEntity();
  }, [location.pathname]);

  return null;
}

Vue Example

// In your router setup
router.afterEach((to) => {
  window.jstag.pageView();
  window.jstag.loadEntity();
});

Controlling Widget Refresh

By default, Pathfora widgets are re-evaluated every time loadEntity loads an updated profile. For SPAs with frequent route changes, this can cause unnecessary flickering. Use listenForProfileChange to only reload widgets when their dependencies change:

jstag.init({
  src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
  pathfora: {
    publish: {
      listenForProfileChange: true
    }
  }
});
  • false (default): All Lytics-managed widgets are removed and re-evaluated every time the profile loads.
  • true: Only widgets with dependencies (audience membership, attribute targeting, entity field templates) are reloaded when those dependencies change.

Accessing Visitor Profiles

The JS Tag fetches the visitor's profile in real-time from the /personalize endpoint. Because this is asynchronous, always use the callback pattern.

Entity Ready Callback

jstag.call('entityReady', function(profile) {
  var user = profile.data.user;

  console.log("Audiences:", user.segments);
  console.log("Email:", user.email);
});

Profile Data Structure

{
  "data": {
    "user": {
      "email": "[email protected]",
      "segments": ["all", "known_users", "high_value"],
      "first_name": "Jane"
    },
    "experiences": [
      {
        "experience_id": "f53e136b35c498ac944b56a0658ab672",
        "experience_slug": "welcome_offer",
        "provider_slug": "custom"
      }
    ],
    "errors": null
  }
}

The segments array contains audience slugs that have been enabled for API access. The user object contains any fields that have been explicitly surfaced in your account settings.

Audience Membership

Via Callback (Recommended)

jstag.call('entityReady', function(profile) {
  var audiences = profile.data.user.segments;

  if (audiences.indexOf('high_value') !== -1) {
    showVIPExperience();
  }
});

Via Direct Method

// Returns audience list (only after profile has loaded)
jstag.getSegments();

Via localStorage (Zero Latency)

Version 3 caches audience membership in localStorage. For use cases that cannot wait for the async profile load:

try {
  var audiences = JSON.parse(localStorage.lytics_segments);
  console.log("Cached audiences:", audiences);
} catch (e) {
  // Audiences not yet cached
}

Reloading the Profile

Force a profile refresh and re-evaluate experiences:

jstag.loadEntity(function(profile) {
  console.log("Profile refreshed:", profile.data);
});

Content Recommendations

The content recommendation plugin fetches personalized content suggestions for the current visitor in real-time.

Basic Usage

jstag.recommend(
  { limit: 5 },
  function(recommendations) {
    recommendations.forEach(function(item) {
      console.log("Recommended:", item.title, item.url);
    });
  }
);

Options

PropertyTypeDescription
limitnumberMaximum recommendations to return
collectionstringTarget a specific content collection
visitedbooleanInclude/exclude previously visited content
shufflebooleanRandomize the order of results
displaystringDisplay context or format
enginestringRecommendation engine to use
ranknumberRanking criteria
waitstringWait condition for processing

Caching Behavior

  • Results are cached in browser storage using a key based on user ID and parameters.
  • Cached results are returned immediately for faster performance.
  • When visited: false is set, the cache is bypassed.
  • When shuffle: true is set, the first item is removed from cached results each time.

Error Handling

function loadRecommendations() {
  var hasLoaded = false;

  var fallbackTimer = setTimeout(function() {
    if (!hasLoaded) displayFallbackContent();
  }, 3000);

  jstag.recommend(
    { limit: 5, collection: "blog-posts" },
    function(recommendations) {
      hasLoaded = true;
      clearTimeout(fallbackTimer);
      if (recommendations.length > 0) {
        displayRecommendations(recommendations);
      } else {
        displayFallbackContent();
      }
    }
  );

  jstag.on("recommend.failure", function() {
    hasLoaded = true;
    clearTimeout(fallbackTimer);
    displayFallbackContent();
  });
}

Debug Events

EventFires When
recommend.requestedRecommendation request is initiated
recommend.successRecommendations are returned successfully
recommend.failureRecommendation request fails
jstag.on("recommend.success", function(recs) {
  console.log("Received", recs.length, "recommendations");
});

jstag.on("recommend.failure", function(error) {
  console.error("Recommendation error:", error);
});

Integration Examples

A common pattern is to forward Lytics profile data to other tools running on the page.

Google Analytics 4

jstag.call('entityReady', function(profile) {
  if (profile && profile.data && profile.data.user) {
    gtag('set', { 'audience_name': profile.data.user.segments });
  }
});

Sitecore

jstag.call('entityReady', function(profile) {
  if (profile && profile.data && profile.data.user) {
    var segs = profile.data.user.segments || [];
    jstag.setCookie("ly_segs", JSON.stringify(segs), 604800);
  }
});

LiveRamp

jstag.call('entityReady', function(profile) {
  var id = profile.data.user._uid;
  var previouslySent = jstag.getCookie("lyticsLrIdl");
  if (!previouslySent) {
    // Send to LiveRamp
    jstag.setCookie("lyticsLrIdl", id, 604800);
  }
});

Generic Pattern

jstag.call('entityReady', function(profile) {
  var user = profile.data.user;
  if (!user) return;

  // Forward audiences to any tool
  var audiences = user.segments || [];
  yourTool.setUserData({
    lytics_audiences: audiences,
    lytics_email: user.email
  });
});

Quick Reference

Methods

MethodUse CaseExample
jstag.send(data)Send custom event datajstag.send({ event: "signup" })
jstag.send(stream, data, cb)Send to specific streamjstag.send('mystream', { event: "signup" }, fn)
jstag.pageView()Track a page viewjstag.pageView()
jstag.call('entityReady', cb)Access visitor profilejstag.call('entityReady', fn)
jstag.loadEntity(cb)Refresh profile & campaignsjstag.loadEntity(fn)
jstag.getEntity()Get current entity datajstag.getEntity()
jstag.getid(cb)Get visitor's anonymous IDjstag.getid(fn)
jstag.setid(val)Set custom anonymous IDjstag.setid('abc123')
jstag.getSegments()Get audience membershipjstag.getSegments()
jstag.recommend(opts, cb)Get content recommendationsjstag.recommend({ limit: 5 }, fn)
jstag.on(event, cb)Listen for eventsjstag.on('entityReady', fn)
jstag.once(event, cb)Listen for event (once)jstag.once('entityReady', fn)
jstag.setCookie(name, val, ttl)Set a browser cookiejstag.setCookie('key', 'val', 86400)
jstag.getCookie(name)Read a browser cookiejstag.getCookie('key')
jstag.mock()Test mode (no real sends)jstag.mock()

Common Event Payloads

// Login
jstag.send({ event: "login", email: "[email protected]", userid: "U123" });

// Registration
jstag.send({ event: "registration", email: "[email protected]", signup_source: "website" });

// Newsletter signup
jstag.send({ event: "newsletter_signup", email: "[email protected]" });

// Product view
jstag.send({ event: "product_viewed", product_id: "SKU-789", product_category: "shoes" });

// Add to cart
jstag.send({ event: "add_to_cart", product_id: "SKU-789", quantity: 1, cart_value: 89.99 });

// Purchase
jstag.send({ event: "purchase_completed", order_id: "ORD-456", order_value: 129.99, currency: "USD" });

// Search
jstag.send({ event: "search", search_query: "running shoes", results_count: 24 });

// Content engagement
jstag.send({ event: "video_played", video_id: "VID-001", video_title: "Demo" });

// File download
jstag.send({ event: "file_downloaded", file_name: "whitepaper.pdf", file_type: "pdf" });

Debugging Commands

Run these in the browser console to inspect the current state:

jstag.config.version          // Tag version
jstag.isLoaded                // True if all resources loaded
jstag.getSegments()           // Current audience membership
jstag.getEntity()             // Full profile data
jstag.getid(id => console.log(id))  // Anonymous visitor ID

Events

EventDescription
entityReadyUser profile has loaded
recommend.requestedRecommendation request initiated
recommend.successRecommendations returned
recommend.failureRecommendation request failed
pathfora.publish.donePathfora widget published

Cookies & Storage

NameTypePurpose
seeridCookieLytics anonymous visitor ID (_uid)
lytics_segmentslocalStorageCached audience membership

Troubleshooting

Is the tag loaded?

jstag.isLoaded    // should return true

If jstag is undefined, the tag snippet is not installed or hasn't loaded yet.

Is data being sent?

Open the Network tab in developer tools and filter for lytics.io. Look for requests to the /c endpoint:

Check the Payload section to see exactly what data was sent:

You can also test from the console:

jstag.send({ event: "test" });

Then verify the event appears in the Network tab and in the Lytics stream/pipeline UI.

Is the profile loading correctly?

Filter the Network tab for requests to the /personalize endpoint:

Use the Preview tab to inspect the returned profile data:

What data is stored client-side?

Two types of data are stored in the browser:

  • Consumer attributes — profile fields like first_name, email, etc. Controlled by your account's surfaced fields settings.
  • Consumer behaviors — audience membership and active experiences/campaigns.

Both are available via:

jstag.getEntity()

Account settings control which attributes are surfaced client-side:

Verifying audience membership

jstag.getSegments();

This returns the list of audiences the current visitor belongs to (only after the profile has loaded).

Testing Best Practices

  • Always use incognito mode. This removes all cookies and caches, ensuring a clean test session. Close all incognito windows between test sessions.
  • Document your testing path. Record the date, time, audience being tested, and results with screenshots.

Testing Known User Audiences

When testing audiences that link email and cookie data:

  • Use each test email only once. Gmail supports punctuation tricks: [email protected] and [email protected] deliver to the same inbox but create separate Lytics profiles.
  • Trigger a merge event to link the cookie with the email:
    • Submit a form that sends email via jstag.send()
    • Open an email link (with tracking pixel) in the incognito window
    • Use the API to force-append an email to the cookie

Testing Anonymous User Audiences

Find your anonymous cookie ID:

jstag.getid(id => console.log(id));

Use this ID to search for your profile in the Lytics dashboard's Find a User feature.

Numbers Not Matching?

When comparing Lytics user counts against other sources:

  • Ensure you're comparing the same time period, web property, and filters.
  • Account for employee traffic and bots.
  • Lytics merges profiles across browsers and devices, so counts may be lower than tools that count unique cookies.
Google Analytics often reports higher numbers because it counts unique page visits per cookie. Lytics counts unique user profiles, which may span multiple cookies/devices. For detailed validation, export raw events or audience membership to BigQuery, S3, or another data warehouse.

Contact Lytics support for assistance with count validation.

API Reference

The JS Tag interacts with two primary APIs:

  • Data Upload — handles collection for all jstag.send() calls via the /c endpoint
  • Personalization — retrieves user profiles and powers onsite personalization via the /personalize endpoint