Lytics JavaScript Tag (jstag) SDK for behavioral tracking, identity resolution, and real-time personalization. Covers jstag.send() for custom events, identity linking, profile access via entityReady, content recommendations, declarative lx-* attribute tracking, and SPA integration patterns. Use when adding Lytics tracking events, identifying users, accessing visitor profiles, or implementing content personalization on a website.
The Lytics JS Tag is the primary SDK for collecting behavioral data from website visitors and delivering real-time personalization. It handles behavioral tracking, identity resolution, profile delivery, and integration handoff.
Paste in your site's <head>:
<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>
If GTM is already installed in app/layout.tsx via next/script, the Lytics tag loads automatically through the GTM Custom HTML tag — no additional code-side work needed.
jstag.init({
src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
loadid: true, // Cross-domain identity (third-party cookie)
stream: 'web_main', // Custom stream name (default: "default")
sessecs: 1800, // Session timeout in seconds
qsargs: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'],
cookies: { domain: '.yoursite.com' } // Cookie domain for subdomain tracking
});
| Key | Type | Default | Description |
|---|---|---|---|
src | string | — | URL to load the tag from (required, provided by Lytics) |
url | string | //c.lytics.io | Collection endpoint URL. Do not change. |
cid | string | — | Account ID (auto-set from src) |
loadid | boolean | false | Enable third-party cookies for cross-domain identity |
stream | string | "default" | Data stream name for collected events |
sessecs | integer | 1800 | Session timeout in seconds (30 min) |
qsargs | string[] | [] | Query parameters to always collect from the URL |
cookies | object | — | Cookie domain config, e.g., { domain: ".site.com" } |
entity | object | — | Custom identifier config (byFieldKey, byFieldValue) |
pageAnalysis | object | — | Control automatic page data collection |
lx | object | — | Declarative tracking plugin config |
Every event automatically includes:
| Field | Description |
|---|---|
_e | Event type (pv = page view) |
_ref | Referral domain |
_tz | Time zone offset |
_ul | Browser language |
_sz | Display size |
_ts | Timestamp (ms since epoch) |
_nmob | Not mobile (t = desktop) |
_device | Device type |
url | Page URL |
_uid | Lytics cookie ID |
Captured automatically on full page loads. For SPAs, call manually:
jstag.pageView();
jstag.send()jstag.send({
event: "button_clicked",
button_name: "hero_cta",
page_section: "homepage"
});
jstag.send(STREAM, PAYLOAD, CALLBACK);
| Parameter | Type | Description |
|---|---|---|
STREAM | string | Target stream name (optional, overrides config default) |
PAYLOAD | object | The data to send |
CALLBACK | function | Called when the collect request completes |
jstag.send('checkout_events', { event: "cart_updated", item_count: 3 }, function(response) {
console.log("Event sent:", response);
});
product_viewed not click)// Good
jstag.send({ event: "product_viewed", product_id: "SKU-123", product_category: "shoes" });
// Bad — nested objects, mixed case
jstag.send({ event: "Product Viewed", order: { id: "ORD-456", total: { value: 129.99 } } });
On first visit, the JS Tag generates a unique _uid stored as a first-party cookie (seerid). This links all activity to a single anonymous profile across sessions.
Send identity data whenever available (login, registration, form submission):
jstag.send({
event: "login",
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/user ID.
Use a stronger identifier for authenticated users instead of the cookie:
var user = getAuthenticatedUser();
var config = {
src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js'
};
if (user && user.id) {
config.entity = {
byFieldKey: 'user_id',
byFieldValue: user.id
};
} else if (user && user.email) {
config.entity = {
byFieldKey: 'email',
byFieldValue: user.email
};
}
jstag.init(config);
jstag.init({
src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
loadid: true
});
jstag.getid(function(id) {
console.log("Visitor ID:", id);
});
jstag.send({ event: "login", email: user.email, userid: user.id });
jstag.send({ event: "registration", email: user.email, signup_source: "website", plan: "free" });
jstag.send({
event: "newsletter_signup",
email: email,
form_name: "footer_newsletter"
});
jstag.send({
event: "contact_form_submitted",
email: formData.email,
name: formData.name,
inquiry_type: formData.subject
});
// Product view
jstag.send({ event: "product_viewed", product_id: "SKU-789", product_name: "Running Shoes", product_price: 89.99 });
// 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", item_count: 2 });
jstag.send({ event: "search", search_query: "running shoes", results_count: 24 });
jstag.send({ event: "video_played", video_id: "VID-001", video_title: "Product Demo", video_duration: 180 });
jstag.send({ event: "file_downloaded", file_name: "whitepaper.pdf", file_type: "pdf" });
Capture automatically via config:
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']
});
lx-* AttributesTrack interactions directly in HTML markup — no JavaScript required.
jstag.init({
src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
lx: { disabled: false }
});
| Attribute | Description |
|---|---|
lx-trigger | DOM event that triggers collection (click, change, submit, etc.) |
lx-send | Query-string style payload (e.g., event=signup&plan=free) |
lx-send-* | Individual payload fields as separate attributes |
lx-stream | Route to a specific stream |
All attributes also work with data- prefix (e.g., data-lx-trigger).
<!-- Button click -->
<button lx-trigger="click" lx-send="event=cta_clicked&button_name=hero_signup">
Sign Up Now
</button>
<!-- Using individual attributes -->
<button lx-trigger="click" lx-send-event="cta_clicked" lx-send-button_name="hero_signup">
Sign Up Now
</button>
<!-- Form submission (auto-collects all field values) -->
<form lx-trigger="submit">
<input name="email" type="email" />
<input name="signup_source" type="hidden" value="footer_newsletter" />
<button type="submit">Subscribe</button>
</form>
<!-- Custom stream -->
<button lx-trigger="click" lx-send="event=download&file=whitepaper.pdf" lx-stream="content_engagement">
Download
</button>
lx-send-* names convert to dots in payload (lx-send-user-name -> user.name)lx-trigger="submit" calls preventDefault() — handle form submission separatelyfunction onRouteChange() {
jstag.pageView();
jstag.loadEntity(function(profile) {
console.log("Profile refreshed:", profile.data);
});
}
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;
}
For Next.js with App Router, track route changes in a client component:
"use client";
import { useEffect } from "react";
import { usePathname } from "next/navigation";
export default function LyticsPageTracker() {
const pathname = usePathname();
useEffect(() => {
if (window.jstag) {
window.jstag.pageView();
window.jstag.loadEntity();
}
}, [pathname]);
return null;
}
Prevent widget flickering on frequent route changes:
jstag.init({
src: '//c.lytics.io/api/tag/YOUR_ACCOUNT_ID/latest.min.js',
pathfora: { publish: { listenForProfileChange: true } }
});
jstag.call('entityReady', function(profile) {
var user = profile.data.user;
console.log("Audiences:", user.segments);
console.log("Email:", user.email);
});
{
"data": {
"user": {
"email": "[email protected]",
"segments": ["all", "known_users", "high_value"],
"first_name": "Jane"
},
"experiences": [
{
"experience_id": "f53e136b35c498ac944b56a0658ab672",
"experience_slug": "welcome_offer"
}
]
}
}
// Via callback (recommended)
jstag.call('entityReady', function(profile) {
var audiences = profile.data.user.segments;
if (audiences.indexOf('high_value') !== -1) {
showVIPExperience();
}
});
// Via direct method (only after profile loaded)
jstag.getSegments();
// Via localStorage (zero latency, cached)
var audiences = JSON.parse(localStorage.lytics_segments);
jstag.loadEntity(function(profile) {
console.log("Profile refreshed:", profile.data);
});
jstag.recommend(
{ limit: 5, collection: "blog-posts", visited: false, shuffle: true },
function(recommendations) {
recommendations.forEach(function(item) {
console.log("Recommended:", item.title, item.url);
});
}
);
| Property | Type | Description |
|---|---|---|
limit | number | Maximum recommendations to return |
collection | string | Target a specific content collection |
visited | boolean | Include/exclude previously visited content |
shuffle | boolean | Randomize order |
jstag.on("recommend.failure", function(error) {
console.error("Recommendation error:", error);
displayFallbackContent();
});
jstag.call('entityReady', function(profile) {
var user = profile.data.user;
if (!user) return;
// Google Analytics 4
gtag('set', { 'audience_name': user.segments });
// Any other tool
yourTool.setUserData({
lytics_audiences: user.segments,
lytics_email: user.email
});
});
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)
| Method | Description |
|---|---|
jstag.send(data) | Send custom event data |
jstag.send(stream, data, cb) | Send to specific stream with callback |
jstag.pageView() | Track a page view |
jstag.call('entityReady', cb) | Access visitor profile |
jstag.loadEntity(cb) | Refresh profile and campaigns |
jstag.getEntity() | Get current entity data |
jstag.getid(cb) | Get visitor's anonymous ID |
jstag.setid(val) | Set custom anonymous ID |
jstag.getSegments() | Get audience membership |
jstag.recommend(opts, cb) | Get content recommendations |
jstag.on(event, cb) | Listen for events |
jstag.once(event, cb) | Listen for event (once) |
jstag.setCookie(name, val, ttl) | Set a browser cookie |
jstag.getCookie(name) | Read a browser cookie |
jstag.mock() | Test mode (no real sends) |
| Event | Description |
|---|---|
entityReady | User profile has loaded |
recommend.requested | Recommendation request initiated |
recommend.success | Recommendations returned |
recommend.failure | Recommendation request failed |
| Name | Type | Purpose |
|---|---|---|
seerid | Cookie | Lytics anonymous visitor ID (_uid) |
lytics_segments | localStorage | Cached audience membership |
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
In the Network tab, filter for lytics.io:
/c endpoint — collection requests from jstag.send()/personalize endpoint — profile fetch requestsCreate a Lytics account — Sign up at lytics.com and get your account ID from Account Settings.
Install the JS Tag — If using GTM, create a Custom HTML tag in the GTM UI with the Lytics snippet, trigger on All Pages, and publish. This is already done if the GTM container has the "Lytics CDP - Initialize" tag.
Configure streams and LQL — Custom streams require corresponding LQL statements in the Lytics app to map raw fields to user profile fields. This is done in the Lytics UI under Data > Streams.
Set up audiences — Create audiences in the Lytics app that will be available via getSegments() and the entityReady callback. Enable API access for audiences you want surfaced client-side.
Surface profile fields — In Lytics Account Settings, configure which user attributes are returned by the /personalize endpoint (and thus available in entityReady callbacks).
Configure content collections — For jstag.recommend(), set up content collections in the Lytics app that define which content is eligible for recommendations.
jstag is defined in the consolesrc URL is correct and accessiblelytics.io/cjstag.send({ event: "test" }) in the console/personalize requestsjstag.getEntity() to inspect current profile data