Skip to main content

SDK Integration Guide

This guide covers the SDK integration path for browser apps, React, Next.js, Angular, Android, and Node.js.

Packages

For browser, React, Next.js, Angular, and Node.js integrations, install the npm package:

npm install @drivemetadata-ai/sdk

For Android integrations, install the Gradle dependency:

dependencies {
implementation 'com.drivemetadata:dmd-android-sdk:1.3.7'
}

Runtime entry points:

RuntimeImport pathUse for
Browser@drivemetadata-ai/sdk/browserPlain JavaScript and browser applications
React@drivemetadata-ai/sdk/reactReact provider and hooks
Next.js@drivemetadata-ai/sdk/nextClient-safe React helpers plus route tracking hooks
Angular@drivemetadata-ai/sdk/angularAngular provider and injectable service
Androidcom.drivemetadata:dmd-android-sdkAndroid client events, deep links, device tokens, uninstall support, and mobile ad metadata
iOSDriveMetaDataiOSSDKNative iOS events, IDFA permission, and universal links
React Nativereact-native-drivemetadataCross-platform mobile SDK initialization, events, and deep-link data
Node.js@drivemetadata-ai/sdk/nodeBackend/server events only

Do not import the Node entry point from browser bundles. Do not initialize the browser SDK during server rendering.

Required Keys

Browser and framework integrations use public browser tokens:

const browserConfig = {
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token'
};

Use camelCase config keys in npm integrations. The backend payload still sends the backend-required metaData shape, but SDK configuration should use clientId, workspaceId, appId, apiHost, capturePageview, capturePageleave, schemaValidation, and beforeSend.

Node integrations use a server token stored only in backend environment variables:

DMD_SERVER_TOKEN=server_write_key

Android, iOS, and React Native integrations use mobile client credentials provisioned for the mobile source. Do not ship a backend/server token in a mobile app.

Environment Variables

For React/Vite-style browser builds, expose only public browser values:

VITE_DMD_CLIENT_ID=client_xxx
VITE_DMD_WORKSPACE_ID=workspace_xxx
VITE_DMD_APP_ID=app_xxx
VITE_DMD_TOKEN=public_token

For Next.js browser integrations, use NEXT_PUBLIC_ only for public browser values:

NEXT_PUBLIC_DMD_CLIENT_ID=client_xxx
NEXT_PUBLIC_DMD_WORKSPACE_ID=workspace_xxx
NEXT_PUBLIC_DMD_APP_ID=app_xxx
NEXT_PUBLIC_DMD_TOKEN=public_token

For Node/server integrations, do not use NEXT_PUBLIC_:

DMD_SERVER_TOKEN=server_write_key

Common Browser Config

const config = {
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token',
apiHost: 'https://sdk.drivemetadata.com/v2',
consent: { analytics: 'pending', advertising: 'denied' },
capturePageview: true,
capturePageleave: true,
schemaValidation: 'warn',
delivery: {
retryDelayMs: 1000,
maxRetryDelayMs: 30000,
maxQueueSize: 100,
useBeacon: true
}
};

Recommended defaults:

OptionRecommendedNotes
consent.analyticspendingGrant after consent manager resolves
capturePageviewtrueSends automatic page views in browser runtimes
capturePageleavetrueSends lifecycle/page leave events
schemaValidationwarnUse strict in controlled integrations after testing
delivery.useBeacontrueHelps lifecycle delivery during navigation

Enterprise integrations should start with analytics consent as pending or denied, then grant it after the consent manager resolves.

consent: {
analytics: 'pending',
advertising: 'denied',
personalization: 'denied',
functional: 'granted',
saleOfData: 'denied'
}

If consent is omitted, analytics defaults to pending and events are dropped until consent is granted.

Browser Integration

import {
consent,
flush,
getDmdHealth,
identify,
initDmdSDK,
page,
track
} from '@drivemetadata-ai/sdk/browser';

const dmd = initDmdSDK({
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token',
consent: {
analytics: 'pending',
advertising: 'denied',
personalization: 'denied',
functional: 'granted',
saleOfData: 'denied'
}
});

consent.update({ analytics: 'granted' });

identify('user_123', { plan: 'enterprise' });
page('Product Page');
track('Product Viewed', { productId: 'sku_123' });

await flush();
console.log(getDmdHealth());

Browser API methods:

MethodUse for
track(event, properties, options)custom events
page(name, properties, options)page views
identify(userId, traits, options)known users
group(groupId, traits, options)accounts/workspaces/organizations
alias(previousId, userId, options)identity merge
flush()force queued delivery
reset()reset identity/session state
setConsent(consent) / consent.update(consent)consent updates
getDmdHealth()diagnostics

Backend Timestamp Fields

Every collector request sends these timestamp fields inside metaData:

FieldFormatNotes
timestampYYYY-MM-DD HH:mm:ssUTC, no milliseconds, no timezone suffix
requestSentAtYYYY-MM-DD HH:mm:ssUTC, no milliseconds, no timezone suffix
requestReceivedAtYYYY-MM-DD HH:mm:ssUTC, no milliseconds, no timezone suffix

If a caller provides an invalid timestamp string, the SDK normalizes it to the current UTC time instead of sending the invalid value to the backend.

Default Page Context

Browser, React, Next.js, and Angular integrations automatically add browser page context to each collector payload.

{
"metaData": {
"page": {
"url": "https://example.com/products/sku-123?utm_source=paid",
"path": "/products/sku-123",
"search": "?utm_source=paid",
"title": "Product Detail",
"referrer": "https://google.com/search?q=%5BREDACTED%5D"
}
}
}

The SDK reads this from window.location, document.title, and document.referrer. Query strings in search and referrer are redacted by default except common attribution parameters such as utm_source, utm_medium, utm_campaign, utm_term, and utm_content.

Node/server integrations do not automatically capture page context. Pass page details explicitly in server event properties if needed.

Default Identity, Session, Attribution

Browser, React, Next.js, and Angular integrations also add these fields by default:

FieldBehavior
requestIdgenerated UUID for each event
anonymousIdpersisted anonymous browser visitor ID
sessionIdpersisted browser session ID with idle timeout
attributionDatastored click IDs and _fbc/_fbp when available
utmParameterstored UTM values when available

The SDK stores anonymous/session/attribution state using the configured browser persistence mode and falls back safely when browser storage is blocked.

React Integration

Wrap the app once:

import { DmdProvider } from '@drivemetadata-ai/sdk/react';

export function App() {
return (
<DmdProvider
config={{
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token',
consent: { analytics: 'pending', advertising: 'denied' }
}}
>
<Routes />
</DmdProvider>
);
}

For Vite React apps, the provider config commonly comes from import.meta.env:

const config = {
clientId: import.meta.env.VITE_DMD_CLIENT_ID,
workspaceId: import.meta.env.VITE_DMD_WORKSPACE_ID,
appId: import.meta.env.VITE_DMD_APP_ID,
token: import.meta.env.VITE_DMD_TOKEN,
consent: { analytics: 'pending' as const, advertising: 'denied' as const }
};

Track from components:

import { useDmdConsent, useDmdFlush, useIdentify, useTrackEvent } from '@drivemetadata-ai/sdk/react';

export function CheckoutButton() {
const track = useTrackEvent();
const identify = useIdentify();
const flush = useDmdFlush();
const consent = useDmdConsent();

async function onClick() {
consent({ analytics: 'granted' });
identify('user_123', { plan: 'enterprise' });
track('Checkout Started', { source: 'cart' });
await flush();
}

return <button onClick={onClick}>Checkout</button>;
}

Next.js App Router

Create a client provider:

'use client';

import { DmdProvider, useDmdAppRouterPageTracking } from '@drivemetadata-ai/sdk/next';
import { usePathname, useSearchParams } from 'next/navigation';
import type { ReactNode } from 'react';

function RouteTracking() {
const pathname = usePathname();
const searchParams = useSearchParams();

useDmdAppRouterPageTracking(pathname, searchParams.toString());

return null;
}

export function AnalyticsProvider({ children }: { children: ReactNode }) {
return (
<DmdProvider
config={{
clientId: process.env.NEXT_PUBLIC_DMD_CLIENT_ID!,
workspaceId: process.env.NEXT_PUBLIC_DMD_WORKSPACE_ID!,
appId: process.env.NEXT_PUBLIC_DMD_APP_ID!,
token: process.env.NEXT_PUBLIC_DMD_TOKEN!,
consent: { analytics: 'pending', advertising: 'denied' }
}}
>
<RouteTracking />
{children}
</DmdProvider>
);
}

Use it from app/layout.tsx:

import { AnalyticsProvider } from './AnalyticsProvider';
import type { ReactNode } from 'react';

export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<AnalyticsProvider>{children}</AnalyticsProvider>
</body>
</html>
);
}

Next.js Pages Router

import type { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { DmdProvider, useDmdPagesRouterPageTracking } from '@drivemetadata-ai/sdk/next';

const config = {
clientId: process.env.NEXT_PUBLIC_DMD_CLIENT_ID!,
workspaceId: process.env.NEXT_PUBLIC_DMD_WORKSPACE_ID!,
appId: process.env.NEXT_PUBLIC_DMD_APP_ID!,
token: process.env.NEXT_PUBLIC_DMD_TOKEN!,
consent: { analytics: 'pending' as const, advertising: 'denied' as const }
};

function PageTracking() {
const router = useRouter();
useDmdPagesRouterPageTracking(router);
return null;
}

export default function App({ Component, pageProps }: AppProps) {
return (
<DmdProvider config={config}>
<PageTracking />
<Component {...pageProps} />
</DmdProvider>
);
}

Angular Integration

Register the provider:

import { ApplicationConfig } from '@angular/core';
import { provideDmdAnalytics } from '@drivemetadata-ai/sdk/angular';

export const appConfig: ApplicationConfig = {
providers: [
provideDmdAnalytics({
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token',
consent: { analytics: 'pending', advertising: 'denied' }
})
]
};

For Angular environment files, keep only the public browser token in frontend config:

export const environment = {
dmd: {
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: 'public_token'
}
};

Initialize and track:

import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core';
import { DmdAnalyticsService } from '@drivemetadata-ai/sdk/angular';

@Component({
selector: 'app-root',
template: '<router-outlet />'
})
export class AppComponent implements OnInit {
constructor(
private readonly dmd: DmdAnalyticsService,
@Inject(PLATFORM_ID) private readonly platformId: object
) {}

ngOnInit() {
if (!isPlatformBrowser(this.platformId)) return;

this.dmd.init();
this.dmd.setConsent({ analytics: 'granted' });
this.dmd.track('App Loaded');
}
}

For Angular Universal, call this.dmd.init() only when isPlatformBrowser(platformId) is true.

Node Server Integration

import { createDmdServerClient } from '@drivemetadata-ai/sdk/node';

const dmd = createDmdServerClient({
clientId: 'client_xxx',
workspaceId: 'workspace_xxx',
appId: 'app_xxx',
token: process.env.DMD_SERVER_TOKEN!,
timeoutMs: 5000,
retry: {
attempts: 3,
minDelayMs: 250,
maxDelayMs: 2000
}
});

await dmd.track({
userId: 'user_123',
event: 'Order Completed',
messageId: 'evt_123',
idempotencyKey: 'order_123',
properties: {
amount: 500,
currency: 'USD'
}
});

Use messageId for a unique event ID and idempotencyKey for business events that may retry, such as orders, invoices, subscriptions, and webhooks.

Server-side page context is explicit:

await dmd.page({
userId: 'user_123',
properties: {
page: {
url: 'https://example.com/orders/123',
path: '/orders/123',
title: 'Order Detail'
}
}
});

Android Client Integration

Use the Android SDK for native mobile event collection, deep links, device token updates, optional mobile ad metadata, and Facebook install referrer support.

dependencies {
implementation 'com.drivemetadata:dmd-android-sdk:1.3.7'
}

Initialize the SDK once from your Application subclass:

import android.app.Application;
import com.drivemetadata.DriveMetaData;

public class App extends Application {
@Override
public void onCreate() {
super.onCreate();

DriveMetaData driveMetaData = new DriveMetaData.Builder(
this,
1234,
"android_client_token",
5678,
"meta_app_id"
).build();

DriveMetaData.setSingletonInstance(driveMetaData);
}
}

Send custom events with JSON properties:

JSONObject properties = new JSONObject();
properties.put("screen", "Checkout");

DriveMetaData.with(this).sendTags(
properties.toString(),
"Checkout Started"
);

For the full Android setup, including manifest permissions, callbacks, deep links, device tokens, ad tracking, debug logs, cleanup, and Meta App ID setup, see Android client integration.

iOS Native Integration

Use the iOS SDK for native app events, IDFA permission, and universal links.

pod 'DriveMetaDataiOSSDK'
import DriveMetaDataiOSSDK

DriveMetaData.initializeShared(
clientId: <DMD_CLIENT_ID>,
clientToken: "<DMD_CLIENT_TOKEN>",
clientAppId: <DMD_CLIENT_APP_ID>
)

For CocoaPods setup, ATT configuration, universal links, and Swift event examples, see iOS native integration.

React Native Integration

Use the React Native plugin for mobile SDK initialization, event metadata, and deep-link background data retrieval.

npm install react-native-drivemetadata
import {sdkInit, sendTags, getBackgroundData} from 'react-native-drivemetadata';

await sdkInit(1234, 'client_token', 5678);
await sendTags({userDetails: {first_name: 'Amit'}}, 'user_registration');

For the full setup, see React Native integration.

Diagnostics

Use health diagnostics when events do not appear:

import { flush, getDmdHealth } from '@drivemetadata-ai/sdk/browser';

console.log(getDmdHealth());
await flush();

Common drop reasons:

ReasonMeaningFix
consent_deniedAnalytics consent is not grantedGrant consent after the consent manager resolves
payload_too_largeEvent exceeds configured payload sizeReduce event properties
queue_limit_exceededOffline queue is fullFlush more often or increase queue size
queue_ttl_expiredEvent stayed offline past TTLIncrease TTL only if business requirements allow it

REST API Ingestion

Use REST API ingestion only from trusted server-side systems. Do not call collector APIs directly from mobile or browser clients. See REST API ingestion.

Backend Payload IDs

The SDK sends requestId, anonymousId, and sessionId as UUID strings in metaData.

{
"metaData": {
"requestId": "019de75e-dd28-779b-8084-2b3091b6de32",
"anonymousId": "019c8fe4-1fc7-7898-8089-f951a8bbfefb",
"sessionId": "019de75e-db3f-75e2-8054-0167411aa4ba"
}
}

Production Checklist

  • Use @drivemetadata-ai/sdk/browser, /react, /next, or /angular only for public browser tokens.
  • Use com.drivemetadata:dmd-android-sdk only with Android client credentials.
  • Use DriveMetaDataiOSSDK and react-native-drivemetadata only with mobile client credentials.
  • Use @drivemetadata-ai/sdk/node only on the server with backend-only environment variables.
  • Start analytics consent as pending or denied until your consent manager grants it.
  • Call flush() before important navigation or checkout completion boundaries when needed.
  • Check getDmdHealth() during integration testing.
  • Verify SSR builds do not initialize browser analytics on the server.