Web SDK

Install the TrueEngage web SDK, track page views and events, identify users and set up web push.

Updated 1 Nov 2026 10 min read

Use the web SDK (@trueengage/web, version 1.0.0) to track events and users on your site and to send web push notifications. It is written in TypeScript, about 12 KB gzipped, and uses no cookies.

Before you start

  • An app key for your site. Use a test_ key while you develop. See Test and Live keys.
  • Your site must run on https. localhost is fine for development.
  • For web push: a Firebase project with Cloud Messaging, its Web Push public key (VAPID key), and the ability to serve a file from your site's root. See Set up web push.

Install

With npm:

npm i @trueengage/web
import TrueEngage from '@trueengage/web';

TrueEngage.initialize({
  appKey: 'test_xxxxxxxx',
  dataRegion: 'in',
});

initialize is synchronous and makes no network call. Call it once, as early as possible. Every other method is safe to call before it, and none of them throws into your page.

Configuration

Pass these fields to initialize. Only appKey is required.

Field Type Default Meaning
appKey string none test_… or live_…. Selects the environment.
apiHost string region host Full base URL. Overrides dataRegion. Must be https (or localhost).
dataRegion 'in' 'in' Picks the API host. India is the only data region today.
logLevel 'none' | 'error' | 'warn' | 'info' | 'verbose' 'error' Console logging.
optOutByDefault boolean false Collect nothing until optIn(). For consent-managed sites.
flushIntervalSeconds number 30 Seconds between timed flushes.
flushBatchSize number 50 Flush when this many items wait.
maxQueueSize number 10000 Items kept before the oldest are dropped.
sessionTimeoutMinutes number 30 Idle time that ends a session.
pageTracking boolean true Send Page Viewed on load and on history changes.
flushOnOptOut boolean true On opt-out, send what is queued first. false deletes it.
push.autoRegister boolean true Subscribe when requestPushPermission() is granted.
push.vapidPublicKey string none The Web Push public key (VAPID key) from Firebase.
push.serviceWorkerPath string '/te-sw.js' Where your site serves the push worker.
push.requestPermissionOnInit boolean false Browsers need a user gesture, so leave this off.
locationPrompt 'manual' | 'auto' 'manual' See Device location.
locationRefreshHours number 4 Minimum hours between location fixes.

Identify and log out

TrueEngage.identify('u-1001', { firstName: 'Priya', plan: 'pro' });
TrueEngage.logout(); // ends the session, keeps the push subscription
TrueEngage.reset();  // full wipe: new anonymous id, queue cleared

Call identify when the visitor signs in, with the same id you use for the user in your own systems. Call logout when they sign out. See Events, attributes and identity for the rules.

Track events and pages

TrueEngage.track('Order Placed', {
  orderId: 'ORD-8891',
  amount: 2499.5,
  itemCount: 3,
  isFirstOrder: true,
  placedAt: new Date(),
  categories: ['footwear', 'sale'],
});

TrueEngage.track('Sync Finished', { rows: 120 }, { nonInteractive: true });

TrueEngage.page(); // a manual Page Viewed

Page Viewed is automatic on load and on history changes. Turn that off with pageTracking: false, then call page() yourself. page() accepts an optional properties object.

User attributes

TrueEngage.setUserAttribute('lifetimeValue', 48200);
TrueEngage.setUserAttributes({ plan: 'pro', city: 'Indore' });
TrueEngage.removeUserAttribute('trialEndsAt');

Reserved attributes have their own setters:

TrueEngage.setEmail('priya@example.com');
TrueEngage.setPhone('+919876543210'); // E.164, not reformatted
TrueEngage.setFirstName('Priya');
TrueEngage.setLastName('Sharma');
TrueEngage.setGender('female');
TrueEngage.setBirthDate(new Date(1995, 3, 12));
TrueEngage.setCity('Indore');
TrueEngage.setRegion('Madhya Pradesh');
TrueEngage.setCountryCode('IN');
TrueEngage.setTimezone('Asia/Kolkata');
TrueEngage.setLocale('en-IN');

Set up web push

Web push is delivered through Firebase Cloud Messaging (FCM). You need three things: a service worker file, the Web Push key pair, and a click handler that asks for permission.

  1. Copy dist/te-sw.js from the package (import path @trueengage/web/sw) to your site and serve it at /te-sw.js. If you already have a service worker, add importScripts('/te-sw.js') to it instead.

  2. Get the public key in the Firebase console: Project settings → Cloud Messaging → Web configuration → Web Push certificates. If there is no key pair yet, generate one. The FCM provider in the console needs only your project id and service account (see Set up providers); the Web Push key goes to the SDK only:

    TrueEngage.initialize({
      appKey: 'test_xxxxxxxx',
      push: { vapidPublicKey: 'YOUR_VAPID_PUBLIC_KEY' },
    });
    
  3. Ask for permission from a user gesture, such as a button click. Chrome ignores the prompt otherwise, and Safari requires a gesture.

    button.onclick = async () => {
      const result = await TrueEngage.requestPushPermission();
      // 'granted' | 'denied' | 'unavailable'
    };
    
  4. Handle taps if you want to route inside your app:

    const off = TrueEngage.on('pushClicked', (p) => {
      router.push(p.deeplink ?? '/');
    });
    

When permission is granted, the SDK subscribes the browser and sends the subscription to TrueEngage. On every later page load it sends the subscription again with the current permission state.

The service worker shows the notification, records Push Received, Push Clicked and Push Dismissed, and opens the link. It opens same-origin links only.

Other methods:

Method Use
subscribePush() Subscribe explicitly when push.autoRegister is false. Returns the subscription or null.
setPushSubscription(subscription) Hand over a subscription you created yourself.
on('pushReceived' | 'pushDismissed', fn) Listen to push events from the worker.
on('tokenRegistered', fn) Called with the subscription endpoint.
on('pushPermissionChanged', fn) Called with the new permission.

on returns a function that removes the listener. Events that happen before your first listener are buffered. See Push notifications for the full picture.

Network type

Every batch carries a networkType with one of four values: wifi, cellular, none or unknown. The values match the Android and iOS SDKs. Browsers share little about the connection, so:

  • wifi is reported for Wi-Fi and for a wired connection. A browser cannot tell them apart.
  • cellular is reported only where the browser says so. Today that is Chromium on Android.
  • none means the browser reports it is offline.
  • unknown is what Safari, Firefox and most desktop browsers send, because they do not expose the connection type.

The value is read for each batch, so a change shows on the next flush.

Referral and share links

createLink makes a short smart link for a share, an invite or a referral. Turn on in-app links in Smart Links, then Settings first. Until then the call rejects with disabled.

try {
  const link = await TrueEngage.createLink({ deepLinkValue: '/product/42', channel: 'invite' });
  navigator.share?.({ url: link.url });   // { url, shortId, linkId, expiresAt }
} catch (e) {
  if (e instanceof TrueEngageLinkError) console.warn(e.code); // 'disabled' | 'rate_limited' | 'invalid' | 'network'
}

It never retries, so retry in your app if you want to. See Links API and webhooks.

Smart link visits and ad clicks

  • Smart link visits. When a smart link sends a visitor to your verified web app, the address carries te_clid. initialize() removes it, exchanges it once and gives you the link payload through TrueEngage.onDeepLink(({ deepLinkValue, params }) => ...). The id works once and expires after 24 hours. See Link domains.
  • Ad clicks. When the landing URL carries utm_*, gclid, gbraid, wbraid, gad_* or fbclid, the SDK records one touch, with the _fbp and _ga cookies when readable. It captures on page load, and when tracking consent is granted later. See See where each user came from.
  • Matching events with your Meta pixel. track() returns { eventId } and accepts an eventId option. Pass the same id to your browser pixel so the two copies are counted once. See Avoid duplicate events with your browser pixel.
  • Store links. TrueEngage.storeLink('android') returns your registered Play Store URL with the visitor's campaign values, so an install keeps its source.

Location

button.onclick = async () => {
  const state = await TrueEngage.requestLocationPermission();
  // 'granted' | 'denied' | 'restricted' | 'not_requested'
};
await TrueEngage.updateLocation(); // true if a new fix was stored; never prompts

The browser gives coordinates only, not a city. It needs https. See Device location.

Consent and opt-out

TrueEngage.optOut();           // everything; persisted; removes the push subscription
TrueEngage.optOutOf('push');   // 'tracking' | 'push' | 'inApp' | 'all'
TrueEngage.optIn();
TrueEngage.optInTo('push');
TrueEngage.isOptedOut('tracking'); // boolean

With optOutByDefault: true, call optIn() after your consent banner is accepted. See Consent and opt-out.

Clearing ad identifiers

optOut() and optOut('tracking') delete the stored advertising id and click-id touch on the device and tell TrueEngage to delete what it holds. The clear is sent even when flushOnOptOut is false, and only if the SDK ever reported an ad identifier.

If your site stops using ad identifiers without opting the person out, clear them yourself:

TrueEngage.clearAdIdentifiers();                       // all kinds
TrueEngage.clearAdIdentifiers(['gclid', 'fbc', 'fbp']); // only these kinds

With a list of kinds, only click-id kinds are cleared from the stored touch; the advertising id is cleared only when you pass no list. reset() does not send a clear. Requires SDK 0.8.1 and a server that supports it; an older server stores the message as an ordinary ad click event. See When ad identifiers are cleared.

Debug and validate

const info = await TrueEngage.debug.getInfo(); // ids, session, queue depth, last flush, counters
TrueEngage.debug.enableValidation();           // logs name and type checks for each event

Set logLevel: 'verbose' while you test. Share the output of getInfo() when you contact support.

Verify it works

  1. Open your site with a test_ key and click through a page or two.
  2. In the console, switch to Test and go to Audience → Users.
  3. Search for the id you passed to identify and open the profile.
  4. Check the activity list for Page Viewed and your own events.

Priya Banerjee's profile (u-1001) on the Overview tab, with recent sends and Push reachable on Android

Troubleshooting

Symptom Likely cause and fix
No user in the console You are looking at the wrong environment. A test_ key writes to Test only.
Nothing is sent, no errors optOutByDefault is on and optIn() was never called, or the visitor opted out. Check isOptedOut('tracking').
Events stop after a while The key was rejected. Calls with a bad key pause for one hour. Check the key and getInfo().
initialize throws with a test_ key You called it again with a different key. Use one key per page load.
Event rejected in the console log The name is reserved, such as Page Viewed. Pick another name.
Push prompt never appears The call was not from a click, the page is not https, or the browser blocked notifications for the site.
Push permission is granted but nothing arrives te-sw.js is not served at the configured path, vapidPublicKey is missing, or the key is not from the same Firebase project as the FCM provider. Open the worker URL in the browser to check it loads.
Location returns restricted The page is plain http, the Geolocation API is missing, or a Permissions-Policy blocks it. Cross-origin iframes need allow="geolocation".