@salesforce/platform-sdk
v11.69.1
Published
Unified runtime SDK for participating in Salesforce application surfaces — Chat, View, Data, Lightning, Telemetry, and Analytics — from a single package.
Maintainers
Keywords
Readme
@salesforce/platform-sdk
Unified runtime SDK for participating in Salesforce application surfaces — Chat, View, Data, Lightning, Telemetry, and Analytics — from a single package.
Installation
npm install @salesforce/platform-sdko11y and o11y_schema are declared as peer dependencies. Consumers that use createAnalytics, createTelemetryTransport, registerTelemetryUploader, or TelemetryUploader must install them alongside this package:
npm install o11y o11y_schemaConsumers that only use the chat, view, data, lightning, or core surfaces still need to install them to satisfy the peer-dep declaration, but the modules are not loaded at runtime unless an analytics/telemetry symbol is imported.
Quick Start
import { createDataSDK, gql } from "@salesforce/platform-sdk";
const sdk = await createDataSDK();
const result = await sdk.graphql?.query<GetAccountsQuery>({
query: gql`
query Accounts {
uiapi {
query {
Account(first: 10) {
edges {
node {
Id
Name {
value
}
}
}
}
}
}
}
`,
});The chat, view, lightning, telemetry, and analytics surfaces follow the same pattern — see Migrating from individual SDK packages for the full set of factories.
Instrumenting a widget
createAnalytics is the recommended entry point for Mosaic widget tiles and other MCP-embedded UI components. It wires an o11y instrumented app, a Proxy-wrapped ChatSDK for auto-instrumentation, global error listeners, and an optional upload transport — all from one call.
import { createAnalytics, createTelemetryTransport, getChatSDK } from "@salesforce/platform-sdk";
const sdk = await getChatSDK();
const transport = createTelemetryTransport({ sdk });
const analytics = await createAnalytics({
appId: "my-mosaic-tile",
sdk,
transport,
});
// Pass `analytics.instrumentedSDK` to widget hosts that expect a `ChatSDK` —
// SDK calls made through it are auto-instrumented.
analytics.trackPageView("AccountTile");
analytics.trackInteraction("account-tile-row", { accountId });
analytics.trackEvent("record_opened", { recordId });
// On widget/app teardown:
analytics.dispose();| Method | When to call |
| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| trackPageView(componentRef) | Widget mounted or navigated to a new component. Consecutive identical calls are deduplicated. |
| trackInteraction(elementId, properties?) | User interacted with a UI element (click, change, submit). |
| trackEvent(eventName, properties?) | Custom business event that isn't an interaction or page view. |
| trackError(error, properties?) | Explicitly report a caught error. Uncaught errors and unhandled promise rejections are captured automatically. |
| dispose() | Removes global error listeners, logs session duration, and flushes the upload buffer. Call once on teardown. |
createAnalytics is async because it constructs a ChatSDK if you don't supply one. To skip the transport (e.g., during local development), omit the transport option — events still flow through o11y but aren't uploaded.
Attributing events to a PFT Id
Attribute analytics events to a Product Feature Taxonomy (PFT) Id so usage rolls up to the correct feature in Salesforce dashboards.
Server side. The MCP server declares the customer PFT Id on the telemetry_upload tool's _meta under the reserved key "sfdc.pftId":
// telemetry_upload tool definition
{
"name": "telemetry_upload",
"_meta": {
"sfdc.pftId": "aJCEE000000FgYP4A0",
},
}See TdxAxlDemoMcpServer.java for a working example.
Widget side. Read the Id via chatSdk.accessToolMetadata() and pass it to createAnalytics. The SDK exports the same key as PFT_META_KEY so the two sides stay in sync:
import { createAnalytics, PFT_META_KEY } from "@salesforce/platform-sdk";
const meta = chatSdk.accessToolMetadata?.<Record<string, unknown>>();
const pftId = meta?.[PFT_META_KEY];
const analytics = await createAnalytics({
appId: "my-widget",
sdk,
transport,
pftId,
});Only PF Ids (KeyPrefix aJC, 15 or 18 chars) are accepted; PFE Ids (aJD) and malformed values are ignored, and the analytics instance simply carries no PFT attribution. Use validatePftId if you want to gate the value yourself before passing it in.
Telemetry transport
createTelemetryTransport buffers o11y envelopes and uploads them via the telemetry_upload tool exposed by the host ChatSDK. Use it directly when you want batching independent of createAnalytics.
import { createTelemetryTransport, getChatSDK } from "@salesforce/platform-sdk";
const transport = createTelemetryTransport({
sdk: await getChatSDK(),
flushInterval: 30_000, // ms; default 30s
maxBufferSize: 65_536, // bytes; default 64 KB
onError: ({ reason, error, droppedCount }) => {
console.warn("[telemetry]", reason, { error, droppedCount });
},
});
transport.enqueue(envelopeBytes);
transport.dispose(); // flush + cleanupBehavior:
- Buffering. Up to
maxBufferSizebytes. On overflow the oldest entries are evicted andonErrorfires withreason: "buffer_overflow"and adroppedCount. - Automatic flush. On
flushInterval, onvisibilitychange→ hidden, onpagehide, and ondispose(). - Upload size limit. Each upload payload is capped at 1 MB (1,048,576 bytes). If a flush exceeds the cap, the oldest envelopes are dropped first until it fits (at least one envelope is always sent) and
onErrorfires withreason: "payload_too_large"and adroppedCount. This bounds server-side serialization cost (W-22952021). - Upload path. Each flush calls
sdk.callTool({ toolName: "telemetry_upload", params: { inputs: [{ envelopes }] } }). If the call rejects,onErrorfires withreason: "tool_call_failed".
Advanced: registerTelemetryUploader
Use registerTelemetryUploader when you already manage your own o11y InstrumentedApp and don't want createAnalytics to create one for you.
import {
registerTelemetryUploader,
createTelemetryTransport,
getChatSDK,
} from "@salesforce/platform-sdk";
import { registerInstrumentedApp } from "o11y/client";
const app = registerInstrumentedApp("my-app", {
/* o11y options */
});
const transport = createTelemetryTransport({ sdk: await getChatSDK() });
const uploader = registerTelemetryUploader(app, {
onEnvelope: (envelope) => transport.enqueue(envelope),
uploadInterval: 10_000,
messagesLimit: 10,
metricsLimit: 10,
enableClickTrigger: true,
enableVisibilityTrigger: true,
});
// On teardown:
await uploader.dispose({ flush: true });uploader.flush(reason) accepts a FlushReason of "manual" | "interval" | "threshold" | "click" | "visibilitychange" | "pagehide" | "dispose" and is exposed via the TelemetryUploadContext passed to onEnvelope.
Migrating from individual SDK packages
This package replaced the seven previously-published per-domain SDK packages. The deprecation shims published as their final 5.x.x versions forwarded every export to @salesforce/platform-sdk and have now been removed:
@salesforce/platform-sdk-core@salesforce/platform-sdk-chat@salesforce/platform-sdk-view@salesforce/platform-sdk-data@salesforce/platform-sdk-lightning@salesforce/platform-sdk-telemetry@salesforce/platform-sdk-analytics
If you're still on those package names, replace each import with @salesforce/platform-sdk and remove the old entries from your package.json. Every factory function and type that was previously published is exported from this package under the same name.
