mcpField
C
contentsquare-react-native-sdk

contentsquare-react-native-sdk

github.com/contentsquareDevelopment242 installsUpdated 1w ago
Repository

About contentsquare-react-native-sdk

A skill that guides AI agents through integrating or upgrading the Contentsquare React Native SDK in client apps. It requires a project healthcheck first and covers setup, tracking, identity, privacy, and session replay.

Key features

  1. 01Runs a Contentsquare project healthcheck
  2. 02Guides SDK installation and configuration
  3. 03Covers screen, event, and transaction tracking
  4. 04Explains identity and privacy APIs
  5. 05Documents session replay controls

Use cases

  1. 01Adding Contentsquare to a React Native app
  2. 02Upgrading an existing SDK integration
  3. 03Troubleshooting project configuration
  4. 04Implementing screen tracking and session replay

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/contentsquare/agents --skill contentsquare-react-native-sdk

After installing, type/contentsquare-react-native-sdkin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
api-reference.md
common-patterns.md
compatibility.md
debugging-and-tooling.md
in-app-features.md
migration.md
screen-tracking.md
session-replay.md
webview-tracking.md

Details

From the project README

Contentsquare React Native SDK Integration

This skill helps AI agents integrate or upgrade the Contentsquare React Native SDK in client applications.

MANDATORY FIRST STEP -- Contentsquare project healthcheck

Before ANY Contentsquare work in a conversation -- integration, debugging, configuration questions, code changes -- run this healthcheck exactly once per conversation. Do not skip it. Do not defer it to later in the task.

  1. Announce it first. Tell the user what you are about to do, for example:

    "Before we start, I'll run a quick healthcheck of your Contentsquare project: I'll ask for your data source ID (or read your app's bundle ids if you don't have one), call the Contentsquare healthcheck endpoint, and show you the current project configuration. Then we'll continue."

  2. Ask the user for their Contentsquare data source ID(s) first. For example: "Do you have a Contentsquare data source ID? There can be one or several, for example one for Android and one for iOS. If so, tell me which platform each one is for." Use only the IDs the user gives -- never invent one.

    • The user gives one or more data source IDs → check by data source ID only (v3). Skip step 3.
    • The user only has an environment ID → check by bundle id only (v2): an environment ID is not a data source ID and never works in the v3 path.
    • The user has none, does not know, or skips the question → check by bundle id only (v2).
  3. Resolve the bundle ids (only without a data source ID) -- a React Native app has TWO, and they are frequently different strings. Resolve each one separately; never assume they match.

    PlatformWhere to read it
    AndroidapplicationId in android/app/build.gradle(.kts) (fall back to namespace, or package in AndroidManifest.xml)
    iOSPRODUCT_BUNDLE_IDENTIFIER in ios/<App>.xcodeproj/project.pbxproj (or CFBundleIdentifier in Info.plist), resolving any $(...) variables
  4. Call the endpoint -- one version only, never both. The platform segment must be literally ios or android. There is no React Native platform value -- never send one.

    With data source IDs (v3), once per ID:

    curl -s "https://mobile-production.content-square.net/healthcheck/android/config/v3/<dataSourceId>.json"
    curl -s "https://mobile-production.content-square.net/healthcheck/ios/config/v3/<dataSourceId>.json"
    

    Query each ID on the platform the user gave for it. If the platform is unknown, query it on each platform present in the project: a non-200 on one platform only means that data source is not set up for it.

    If an ID gets no 200 on any platform you queried, tell the user -- it may be an environment ID or a typo -- and ask whether you may look for the data source ID in the code yourself: it is the ID passed to StartConfig.withDataSourceId(id, ...) (follow it to its literal value if it comes from a constant or a config file). If they agree and you find a different ID, run the v3 check once with it. If they decline or there is none in the code, continue without it.

    Without a data source ID (v2), once per platform that exists:

    curl -s "https://mobile-production.content-square.net/healthcheck/android/config/v2/<androidApplicationId>.json"
    curl -s "https://mobile-production.content-square.net/healthcheck/ios/config/v2/<iosBundleId>.json"
    

    If only one platform is present in the project, query only that one. If you cannot resolve one of the bundle ids, ask the user which platform to check rather than guessing.

  5. Report a short summary of these values, for each call that returned 200:

    ReportJSON path
    Project IDcs_project_id
    Tracking enabledproject_configurations.project_config.enabled
    Session Replayproject_configurations.project_config.session_replay -- recording_rate, record_via_cellular_network, recording_quality_wifi, srm_enabled, user_identifier
    Enabled feature flagsproject_configurations.project_config.feature_flags -- only entries where enabled == true, with name and min_version

    For v3 calls, also report the Environment ID (environment_id).

    Android and iOS may map to different Contentsquare projects. If the responses differ, call that out explicitly.

  6. Then continue with the user's actual request.

Failure handling. 403 Invalid health-check path means the URL shape is wrong -- re-check the ios/android segment, the v2/v3 segment and the id, and do not alter the path structure. A non-200 proxied from upstream means that data source ID or bundle id has no Contentsquare configuration for that platform: say so, then continue anyway -- do not retry with the other version (the only retry is the code lookup in step 4). This healthcheck is informational only and must never block the user's task.

Install

{
  "dependencies": {
    "@contentsquare/react-native-bridge": "^6.0.1"
  }
}

Then run npm install or yarn install.

iOS Setup
cd ios && pod install && cd ..
Android Setup

No additional setup required after npm install.

Quick Start

import { CSQ, StartConfig } from '@contentsquare/react-native-bridge';
import { useEffect } from 'react';

function App() {
  useEffect(() => {
    // Start the SDK with Product Analytics
    CSQ.start(StartConfig.withEnvironmentId('your-env-id', {
      enableRNAutocapture: true,
      sessionReplayAutoStart: true  // Optional: auto-start session replay
    }));
    
    // TODO: customer to manage consent — call only after user accepts
    CSQ.optIn();
  }, []);

  return <YourApp />;
}

Critical: Never call optIn() without a user consent flow. This is a legal requirement.

It is very important that screens should be tracked, otherwise Session Replay will not work. Track screens manually with trackScreenview() or use React Navigation integration (see Screen Tracking).

Before wrapping the MVP, make sure you are handling WebViews if they are present in the app. WebViews are not automatically tracked, and every WebView must be wrapped. Check the WebView section below for details.

API Surface

Always use CSQ from @contentsquare/react-native-bridge. The Contentsquare default export is deprecated.

Lifecycle
MethodPurpose
start(config?)Start the SDK. Must be called before any other API.
stop()Shut down the SDK completely.
pauseTracking()Pause data collection (for sensitive screens). Avoid unless explicitly requested.
resumeTracking()Resume after pauseTracking().
StartConfig Variants
FactoryUse CaseOnboarding priority
StartConfig.withDataSourceId(id, options?)CSQ with data source ID1st choice for new clients -- ask for this first
StartConfig.withEnvironmentId(id, options?)Product Analytics with environment ID2nd choice if no data source ID is available
StartConfig.dxa()Digital Experience Analytics only (default)Fallback only -- when neither ID is available or DXA-only is explicitly requested

withDataSourceId and withEnvironmentId accept the same AnalyticsOptions object (see the AnalyticsOptions section below). StartConfig.dxa() takes no arguments -- it has no AnalyticsOptions parameter.

Recommended onboarding flow:

  1. Ask the user: "Do you have a Contentsquare data source ID?" (skip the question if they already answered it during the healthcheck). If yes, use StartConfig.withDataSourceId(id, ...).
  2. If not, ask: "Do you have an environment ID?" If yes, use StartConfig.withEnvironmentId(id, ...).
  3. Only if neither is available (or the user explicitly wants DXA-only), fall back to StartConfig.dxa().

Do not invent an ID. Do not silently default to DXA without asking.

Privacy
MethodPurpose
optIn()Opt the device into tracking. Starts immediately.
optOut()Opt out permanently. Stops until optIn() or app reinstall.
Identity
MethodContextPurpose
identify(userIdentifier)Product AnalyticsSet user identity. Different ID triggers new session.
resetIdentity()Product AnalyticsClear identity. Triggers new session.
sendUserIdentifier(userIdentifier)DXASend hashed user ID. Max 100 chars.
Screen Tracking
MethodPurpose
trackScreenview(screenName, customVars?)Track a screen view with optional custom variables.

CustomVar structure: { index: number, key: string, value: string } -- index (1-20), key (max 50 chars), value (max 255 chars).

See Screen Tracking Integration for React Navigation examples.

Transactions
import { CSQ, Currency } from '@contentsquare/react-native-bridge';

CSQ.trackTransaction({
  price: 29.99,
  currency: Currency.USD,
  id: 'order_123'
});

Currency is an ISO 4217 enum (e.g., Currency.USD, Currency.EUR).

Custom Events and Properties
MethodPurpose
trackEvent(eventName, properties?)Track a named event with optional properties.
addDynamicVar(key, value, onError?)Add session-level dynamic variable (DXA only).
addUserProperties(properties)Set user-level properties (PA only).
addEventProperties(properties)Set properties on all future events (PA only).
removeEventProperty(name)Remove one event property.
clearEventProperties()Remove all event properties.

Property values must be string, number, boolean, or bigint. Other types are silently ignored.

Dynamic variables (DXA only):

  • key: string (max 50 chars)
  • value: string (max 255 chars) or unsigned integer (0 to 2^32-1)
  • onError: optional callback for validation errors
Session Replay
MethodPurpose
startSessionReplay()Start Session Replay on-demand. Use when sessionReplayAutoStart: false was passed to start(). One-shot -- not a restart API.
stopSessionReplay()Stop Session Replay on-demand without stopping the SDK. Terminal -- SR cannot be re-started afterwards in the same SDK lifetime.

On-demand Session Replay -- disable auto-start at SDK launch and control it manually:

CSQ.start(StartConfig.dxa());
// Note: sessionReplayAutoStart defaults to false, no need to pass options

// later, when you want SR to start (e.g., entering a checkout flow):
CSQ.startSessionReplay();

// and to stop it (final -- no restart afterwards):
CSQ.stopSessionReplay();

startSessionReplay / stopSessionReplay are start + stop only, not pause/resume. After stopSessionReplay() SR stays off until the next SDK lifetime.

Session Metadata (get replay link)

Access session information including the replay URL. onMetadataChange returns an unsubscribe function -- call it to remove the listener (e.g., on component unmount):

import { useEffect } from 'react';

useEffect(() => {
  const unsubscribe = CSQ.onMetadataChange((metadata) => {
    console.log('Session Replay URL:', metadata.sessionReplayUrl);
    console.log('Session ID:', metadata.sessionID);
    console.log('User ID:', metadata.userID);
  });

  return unsubscribe; // Cleanup on unmount
}, []);

Metadata fields: projectID, environmentID, userID, identity, sessionID, sessionReplayUrl (string or null).

Debug
APIPurpose
setLogLevel(LogLevel)Set log level (info, verbose, etc.)
setLogChannel(LogChannel)Set log output channel
logToConsole()Enable console logging
AnalyticsOptions (shared by withDataSourceId and withEnvironmentId)

StartConfig.dxa() does not accept AnalyticsOptions. The options below apply only to withDataSourceId and withEnvironmentId.

All fields are nullable (undefined = native default behavior).

FieldTypePurpose
enableRNAutocaptureboolean?Enable React Native interaction autocapture (PA)
sessionReplayAutoStartboolean?If true, SR starts at SDK launch. Default: false
uploadIntervalnumber?Upload interval in milliseconds (default: 15000)
baseUrlstring?Custom API endpoint (e.g., for EU data residency)
disablePageviewAutocaptureboolean?Disable automatic screen tracking
disableInteractionAutocaptureboolean?Disable automatic touch tracking (iOS only)
disableInteractionTextCaptureboolean?Disable text capture in interactions (iOS only)
disableInteractionAccessibilityLabelCaptureboolean?Disable accessibility label capture (iOS only)
disablePageviewTitleAutocaptureboolean?Disable page title capture (iOS only)
enablePushNotificationAutocaptureboolean?Capture push notification events
enablePushNotificationTitleAutocaptureboolean?Capture push notification title
enablePushNotificationBodyAutocaptureboolean?Capture push notification body

Session Replay Masking

Global masking (setDefaultMasking)
import { CSQ } from '@contentsquare/react-native-bridge';

// Mask everything by default
CSQ.setDefaultMasking(true);

// Unmask everything (use with caution - privacy risk)
CSQ.setDefaultMasking(false);

Important:

  • setDefaultMasking takes a boolean, not a configuration object. It's all-or-nothing global masking.
  • setDefaultMasking must be called after CSQ.start(...). Calling it before start() has no effect.
Scoped masking (per component)
import { CSQMask } from '@contentsquare/react-native-bridge';

<CSQMask isSessionReplayMasked={true}>
  <Text>Sensitive content</Text>
</CSQMask>

Note: isSessionReplayMasked controls Session Replay visual masking. Use allow* props to also control Product Analytics event data.

Fine-grained control with allow* props (Product Analytics)
<CSQMask 
  isSessionReplayMasked={true}  // Masks visual content in Session Replay
  allowText={false}             // Prevents text in PA events
  allowInteraction={false}      // Prevents interaction tracking in PA events
>
  <TextInput placeholder="Password" />
</CSQMask>

Important: Only isSessionReplayMasked affects Session Replay visual masking. The allow* props control Product Analytics event data capture.

CSQMask props
PropTypeDefaultPurposeFeature
isSessionReplayMaskedboolean?trueWhether to mask visual contentSession Replay
ignoreTextOnlyboolean?falseIgnore text only (conflicts with allow*)Product Analytics
allowInnerHierarchyboolean?falseAllow inner view hierarchy in eventsProduct Analytics
allowPropsboolean?falseAllow view properties in eventsProduct Analytics
allowTextboolean?falseAllow text content in eventsProduct Analytics
allowInteractionboolean?falseAllow interaction tracking in eventsProduct Analytics
allowAccessibilityLabelboolean?falseAllow accessibility labels in eventsProduct Analytics

Important: Only isSessionReplayMasked affects Session Replay visual masking. The allow* props control Product Analytics event data capture. When ignoreTextOnly is true, all allow* props are ignored.

Higher-Order Component masking
import { withCSQMask } from '@contentsquare/react-native-bridge';

const MaskedComponent = withCSQMask(SensitiveComponent, {
  isSessionReplayMasked: true,  // SR visual masking
  allowText: false              // Optional: PA event data masking
});

Screen Tracking Integration

Manual tracking
import { CSQ } from '@contentsquare/react-native-bridge';
import { useEffect } from 'react';

function ProductScreen() {
  useEffect(() => {
    CSQ.trackScreenview('ProductDetails', [
      { index: 1, key: 'product_id', value: '12345' }
    ]);
  }, []);

  return <ProductView />;
}
React Navigation integration

Track screen views automatically using React Navigation's navigation state listener:

import { NavigationContainer } from '@react-navigation/native';
import { CSQ } from '@contentsquare/react-native-bridge';

function App() {
  const navigationRef = useRef();
  const routeNameRef = useRef();

  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() => {
        routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
      }}
      onStateChange={() => {
        const previousRouteName = routeNameRef.current;
        const currentRouteName = navigationRef.current?.getCurrentRoute()?.name;

        if (previousRouteName !== currentRouteName) {
          CSQ.trackScreenview(currentRouteName);
        }

        routeNameRef.current = currentRouteName;
      }}
    >
      <YourNavigator />
    </NavigationContainer>
  );
}

See references/screen-tracking.md for more examples.

WebView Tracking

WebViews are not automatically tracked. Wrap them with CSQWebView to enable session stitching between native and web content. The web pages must include the Contentsquare Web Tracking Tag in WebView mode.

import { CSQWebView } from '@contentsquare/react-native-bridge';
import { WebView } from 'react-native-webview';

<CSQWebView>
  <WebView source={{ uri: 'https://example.com' }} />
</CSQWebView>

Legacy wrapper (deprecated, use CSQWebView):

import { CSWebView } from '@contentsquare/react-native-bridge';

<CSWebView>
  <WebView source={{ uri: 'https://example.com' }} />
</CSWebView>

Important Rules

  • Ask for the environment ID first: Before integrating, ask the user for their Contentsquare environment ID (or data source ID -- reuse the healthcheck answer). Do not assume DXA-only mode, do not invent an ID, and do not skip this step.
  • Scan for WebViews: During integration, search the codebase for any existing WebView usage (react-native-webview, WebView component). WebViews are not automatically tracked -- every WebView must be wrapped with CSQWebView.
  • Call start(config) with appropriate configuration before any other CSQ method
  • Always implement a consent flow before calling optIn() -- never auto-opt-in
  • optOut() is permanent until optIn() is called or the app is reinstalled
  • identify() is for Product Analytics only; sendUserIdentifier() is for DXA only
  • Property values must be string, number, boolean, or bigint -- other types (arrays, objects) are silently ignored or may cause unexpected behavior
  • CustomVar constraints: key max 50 chars; string value max 255 chars; number: 0 to 2^32-1
  • userIdentifier: max 100 characters
  • React Native >= 0.71.0 required (bridge v6.2.0+ supports all versions from 0.71.0 onwards)
  • Android and iOS only (no web, Expo Go, or desktop support)
  • Never expose PII (emails, passwords, real names) in screen names, event names, or property values
  • Never hardcode environment IDs -- use config or environment variables
  • Check Compatibility Guide for Expo, hybrid apps, and known limitations

Autocapture (Product Analytics)

Autocapture enables automatic tracking of user interactions and screen navigation without manual instrumentation.

Prerequisites

Install the Babel plugin in your babel.config.js:

module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: ['@contentsquare/react-native-bridge/babel'],
};

The Babel plugin requires @babel/plugin-transform-react-display-name to include component names in events. This is typically provided by React Native's default preset.

Monorepo setup: If your project uses a monorepo structure (Yarn Workspaces, pnpm, Lerna, Nx, Turborepo, etc.), make sure to add the plugin to all relevant babel.config.js files in your project, including those in any packages that contain React Native code.

Enable Autocapture
import { CSQ, StartConfig } from '@contentsquare/react-native-bridge';

CSQ.start(StartConfig.withEnvironmentId('your-env-id', {
  enableRNAutocapture: true  // Enable autocapture
}));
Navigation Library Compatibility

The React Native Bridge's autocapture feature is compatible with the following navigation libraries:

  • React Navigation: 5.0 and later
  • React Native Navigation: 7.0 and later
What Gets Autocaptured

Autocapture automatically tracks:

  • Touch events (tap, long press, swipe)
  • Change events (text input, switches, pickers, sliders)
  • Component interactions with display names
  • Screen navigation (when enabled)
Combined with Experience Analytics

When using both Experience Analytics and Product Analytics, pass PA options via StartConfig.withDataSourceId:

CSQ.start(StartConfig.withDataSourceId('YOUR_DATA_SOURCE_ID', {
  enableRNAutocapture: true,
  disablePageviewAutocapture: true, // Let Experience Analytics handle screens
}));

Source Maps and Crash Symbolication

For readable JavaScript crash stack traces in production, configure source map upload:

Quick Setup
  1. Install the Contentsquare CLI:

    yarn add @contentsquare/react-native-cli --dev
    
  2. Create contentsquare-cli.json at project root with API credentials and source map paths

  3. Configure build scripts:

    • Android: Add apply from: "../../node_modules/@contentsquare/react-native-cli/scripts/contentsquare.gradle" to app/build.gradle
    • iOS: Add Contentsquare CLI script to Xcode build phase
  4. Add to .gitignore:

    contentsquare-cli.json
    contentsquare-sourcemap-info.json
    

See Debugging and Tooling for complete setup instructions and troubleshooting.

Platform Support

  • Android: Full support
  • iOS: Full support (check iOS compatibility requirements)
  • React Native: >= 0.71.0 (version 6.2.0 supports all current and future versions from 0.71.0 onwards)
  • Expo: Requires EAS (Expo Application Services) - see Compatibility Guide
  • Not Supported: Web, Windows, macOS, Expo Go

Important: Hybrid applications (React Native components in native apps) are not officially supported. For mixed codebases, use native SDKs for native screens and the CSQ bridge for React Native screens.

See Compatibility Guide for detailed version matrices, Expo configuration, and known limitations.

Reference Documentation

Comments

Markdown supported