TypeScript-SDK
Ein Paket mit sechs Einstiegspunkten. Importieren Sie den, der zu Ihrer Laufzeit passt, und der Tree-Shaking-Build lässt den Rest aus Ihrem Bundle.
Wo es veröffentlicht ist
@prodantix/sdk on npm.
Installation
bun add @prodantix/sdkEinstiegspunkte
Jeder Unterpfad liefert seinen eigenen ESM- und CommonJS-Build mit eigenen Typen. Die Wurzel ist laufzeitunabhängig, die übrigen ergänzen, was eine bestimmte Laufzeit braucht.
| Subpath | What it exports |
|---|---|
| @prodantix/sdk | ProdantixClient, createClient, evaluateFlag, FlagsClient, MessagesClient |
| @prodantix/sdk/web | createWebClient, installAutocapture, installLinkCarry, installSessionReplay, WebTransport |
| @prodantix/sdk/node | createNodeClient, readSharedIdentity |
| @prodantix/sdk/csp | prodantixConnectSrc, prodantixImgSrc, prodantixScriptSrc |
| @prodantix/sdk/chat | mountChat, ChatClient, ChatPanel, resolveAppearance |
| @prodantix/sdk/messenger | fetchMessengerConfig, cachedMessengerConfig, MESSENGER_CACHE_KEY |
@prodantix/sdk
Der Client, der Flag-Auswerter sowie die Speicher- und Transportschnittstellen. Nichts davon fasst das DOM an, Sie können also eigenen Speicher, Transport, eine eigene Uhr oder ID-Fabrik übergeben und es überall ausführen.
import { createClient, MemoryStorage } from '@prodantix/sdk';
const prodantix = createClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
storage: new MemoryStorage(),
});
prodantix.capture('order.completed', { properties: { amount: 4200, currency: 'XAF' } });
await prodantix.flush();@prodantix/sdk/web
Browser-Verdrahtung über demselben Client: Persistenz im lokalen Speicher, Zustellung per Beacon, wenn die Seite ausgeblendet wird, sowie Autocapture von Seitenaufrufen und Klicks. Session Replay bleibt aus, bis Sie einen Replay-Host angeben.
import { createWebClient } from '@prodantix/sdk/web';
const prodantix = createWebClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
flagsHost: 'https://api.prodantix.com',
cookieDomain: 'example.com',
autocaptureOptions: { clicks: true, pageviews: true },
});
prodantix.identify('user-42', { set: { plan: 'pro' } });
if (await prodantix.isFeatureEnabled('new-checkout')) {
// ...
}
// Every per-flag read records one $feature_flag_called exposure.
const variant = await prodantix.getVariant('new-checkout');
if (variant?.key === 'treatment') {
// ...
}
// A flag targeting a cohort reads this user's memberships from the store;
// pass them yourself to skip the lookup.
if (await prodantix.isFeatureEnabledLocal('members', { cohorts: ['<cohort id>'] })) {
// ...
}Im Web liegen die anonyme ID und die Sitzung des Besuchers in einem einzigen First-Party-Cookie auf Ihrer registrierbaren Domain, sodass xyz.com, app.xyz.com und console.xyz.com eine Person sehen: Der Marketing-Besuch, die Registrierung und die erste Sitzung in der App landen auf derselben Zeitleiste, sobald die App die Person identifiziert. Die identifizierte ID bleibt je Origin im lokalen Speicher und gelangt nie in das Cookie, weil jeder Host unter der Domain es lesen kann. Die Domain wird durch Nachfragen beim Browser ermittelt oder mit cookieDomain gesetzt; eine Site, deren Subdomains verschiedenen Mandanten gehören, muss sie auf ihren eigenen Host setzen. Übergeben Sie sharedStorage, um kein Cookie zu schreiben, etwa bis eine Einwilligung vorliegt; der lokale Speicher bleibt der Rückfall, wenn Cookies abgelehnt werden. Pro Besuch wird eine Sitzungs-ID erzeugt, nach dreißig Minuten Inaktivität oder vierundzwanzig Stunden rotiert, auf jedes Ereignis gestempelt und mit dem Session Replay geteilt.
Ein Cookie kann keine registrierbare Domain überschreiten, ein Besucher, der einem Link von einer Website zur nächsten folgt, wäre also zwei Besucher. Übergeben Sie linkedDomains, standardmäßig leer, und der Client versieht ausgehende Links zu diesen Domains bei click und auxclick mit einem _pdx-Parameter, der drei Dinge trägt: die anonyme ID, die Sitzungs-ID und den Moment, in dem die Sitzung begann, sodass das Fenster von dreißig Minuten und die Obergrenze von vierundzwanzig Stunden über den Sprung hinweg weiterlaufen. Nur die anonyme ID reist mit, nie eine identifizierte, denn das Ziel identifiziert die Person selbst. Ein Link auf dieselbe registrierbare Domain, ein Link, der bereits _pdx trägt, sowie mailto-, tel-, javascript- und Ankerlinks bleiben allesamt unangetastet. Bei der Ankunft liest createWebClient _pdx, bevor die Identität aufgebaut wird, schreibt die mitgebrachte ID und Sitzung in den gemeinsamen Speicher und entfernt den Parameter mit history.replaceState, sodass er weder in $current_url auftaucht noch weiterreist; ein Parameter, dessen drei Teile sich nicht lesen lassen, wird ignoriert und die Adresse bleibt, wie sie war. Hielt dieser Host bereits eine andere anonyme ID, sendet der Client $create_alias, sodass das zuvor Aufgezeichnete in die mitgebrachte ID einklappt; und ein Host, der bereits eine Person identifiziert hat, behält diese Person: Die mitgebrachte ID wird ihre anonyme ID, nie ihre Distinct-ID.
import { createWebClient } from '@prodantix/sdk/web';
const prodantix = createWebClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
linkedDomains: ['example.com', 'example-app.com'],
});
// A link to example-app.com now leaves as
// https://example-app.com/pricing?_pdx=<anonymousId>~<sessionId>~<startedAt>
// and the arriving page adopts it before it builds an identity of its own.
// The visitor's answer, from your own consent banner.
prodantix.setConsent({ identityLink: false });
prodantix.consent(); // { identityLink: false }Die Antwort des Besuchers selbst zu dieser Zusammenführung reist im selben gemeinsamen Speicher, unter pdx..consent, sodass jede Subdomain und ein Server, der das Cookie liest, eine Antwort sehen. Halten Sie sie mit setConsent({ identityLink: false }) fest, lesen Sie sie mit consent() zurück und säen Sie sie über die Option consent, wenn Ihre Anwendung die Antwort bereits hat: Das Einwilligungsbanner bauen Sie, und prodantix respektiert, was es einsammelt. Solange identityLink false ist, sendet identify keine anonyme ID zur Zusammenführung mit der Person, und ein Link auf eine gelistete Domain bleibt unverziert, denn die ID hinüberzutragen ist dieselbe Zusammenführung auf anderem Weg. Nicht gesetzt oder true erlaubt beides, vorbehaltlich der projekteigenen Einstellung in der Konsole, die der State-Worker durchsetzt und nicht irgendetwas, das der Browser sendet. Eine geänderte Antwort greift beim nächsten identify und beim nächsten Klick; nichts bereits Zusammengeführtes wird getrennt.
@prodantix/sdk/node
Derselbe Client mit Server-Voreinstellungen. Ereignisse werden gepuffert und im Hintergrund gesendet, rufen Sie also shutdown auf, bevor der Prozess endet, sonst geht der letzte Stapel nie hinaus.
import { createNodeClient } from '@prodantix/sdk/node';
// A node client streams flag changes over Socket.IO by default and refetches
// the snapshot on push; streamFlags: false leaves only the 30s poll.
const prodantix = createNodeClient({
apiKey: process.env.PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
streamFlags: true,
});
prodantix.capture('job.completed', { properties: { queue: 'emails' } });
await prodantix.shutdown();Eine Anmeldung, die mit einer Server-Weiterleitung endet, zeichnet keine Seite, das identify des Browsers läuft dort also nie. readSharedIdentity(cookieHeader, apiKey) liest das Cookie, das der Web-Client schreibt, und antwortet mit der anonymen ID, der Sitzung, in der sie steckt, und der Einwilligung des Besuchers, oder mit null, wenn das Cookie fehlt oder nicht zu diesem SDK gehört. link(distinctId, anonymousId, traits) sendet dann das eine $identify, das der Browser gesendet hätte, für die übergebenen IDs, und lässt die eigene Identität dieses Clients unangetastet. Das Login von Bomdisoft ruft beide beim Abschluss der Anmeldung auf, in der einen Funktion, die alle acht seiner Anmeldestellen ohnehin aufrufen: Dort wird das subject der Person auf dem Server zuerst bekannt, während das Cookie noch an der Anfrage hängt. Sechs dieser Stellen sind Server-Aktionen ohne Anfrageobjekt, weshalb die Funktion einen Cookie-Header-String und keine Anfrage entgegennimmt. Überspringen Sie link, wenn die zurückgelesene Antwort identityLink false lautet.
import { createNodeClient, readSharedIdentity } from '@prodantix/sdk/node';
const prodantix = createNodeClient({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.api.prodantix.com',
});
// At sign-in completion, where the person is known and the browser's
// cookie is still on the request.
export const completeSignIn = (sub: string, cookieHeader: string): void => {
const shared = readSharedIdentity(cookieHeader, PRODANTIX_PUBLIC_KEY);
if (shared !== null && shared.consent?.identityLink !== false) {
prodantix.link(sub, shared.anonymousId);
}
};@prodantix/sdk/csp
Die Content-Security-Policy-Quellen, die eine App braucht, um Prodantix zu erreichen. Es importiert nichts aus React oder dem Browser, eine Build-Konfigurationsdatei kann es also direkt lesen.
import { prodantixConnectSrc, prodantixImgSrc, prodantixScriptSrc } from '@prodantix/sdk/csp';
const hosts = {
ingest: 'https://eu.api.prodantix.com',
edge: 'https://eu.edge.prodantix.com',
replay: 'https://eu.replay.prodantix.com',
};
const policy = [
`connect-src ${prodantixConnectSrc(hosts)}`,
`script-src ${prodantixScriptSrc(hosts)}`,
`img-src ${prodantixImgSrc(hosts, ["'self'", 'data:'])}`,
].join('; ');Das Support-Widget zeigt die Bilder Ihres Teams vom Edge und zeichnet die Dateien, die Besucher senden, aus blob:-Adressen, daher braucht img-src in der Richtlinie beides. prodantixImgSrc ergänzt beides zu den Bildquellen, die Sie bereits erlauben. Ohne sie blockiert der Browser diese Bilder und meldet das nur in seiner eigenen Konsole.
@prodantix/sdk/chat
Das Support-Widget. Hängen Sie es ein, und Sie erhalten einen Handle zum Öffnen, Schließen, Zerstören und Identifizieren. Es rendert in einer geschlossenen Shadow Root, die Stile der Gastseite erreichen es also nie.
import { mountChat } from '@prodantix/sdk/chat';
const messenger = mountChat({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
distinctId: prodantix.distinctId,
});
document.querySelector('#help')?.addEventListener('click', () => messenger.open());Jede Besuchernachricht trägt mit, wo sie geschrieben wurde. Das Panel liest im Moment des Sendens location und document.title und schickt host, path und title, wobei path allein der Pfadname ist: nie die Abfrage und nie das Fragment, denn ein Zurücksetzen-Link, ein Magic Link oder eine Rückkehr aus der Kasse trägt sein Token dort, und der Posteingang eines Agenten ist nicht der Ort dafür. Das Panel zeichnet nichts davon, sodass der Strang des Besuchers seine eigenen Worte bleibt, und die Antwort der Edge an das SDK lässt es ebenfalls weg, sodass eine Seite, die ihren eigenen Strang liest, nicht sieht, was die Konsole sieht. Zu sehen ist es im Posteingang, als gedämpfte Zeile unter einem eingehenden Beitrag.
@prodantix/sdk/messenger
Der Einstellungsleser hinter dem Widget: Er holt die Messenger-Konfiguration eines Projekts, legt sie im Cache ab und meldet, ob das Projekt den Messenger aktiviert hat. Das selbstausführende Snippet wird separat gebaut und ist über diesen Unterpfad nicht erreichbar.
import { fetchMessengerConfig } from '@prodantix/sdk/messenger';
const config = await fetchMessengerConfig({
apiKey: PRODANTIX_PUBLIC_KEY,
host: 'https://eu.edge.prodantix.com',
});
if (config?.enabled) {
// the project has the messenger switched on
}