---
title: "Analytics customization"
slug: "analytics-customization"
abstract: "Learn how to override the default analytics implementation and register additional plugins and adapters in a Content SDK Angular app."
---
# Analytics customization

This topic covers how to replace the default analytics registration with your own implementation, and how to register additional plugins, options, or a custom adapter. For what plugins and adapters are and which ones the Angular integration registers by default, see [Plugins](https://doc.sitecore.com/sai/en/developers/content-sdk/angular/1x/plugins.html) and [Adapters](https://doc.sitecore.com/sai/en/developers/content-sdk/angular/1x/adapters.html).

## Overriding the default implementation

The default implementation is a dependency injection (DI) provider, so you replace it the same way you replace any Angular provider: register your own `SITECORE_ANALYTICS` provider **after** `provideSitecoreAngular()` in the `providers` array. This overrides the built-in implementation.

### Implement the interface

Your implementation must satisfy `SitecoreAnalyticsWrapper`, exported from `@sitecore-content-sdk/angular`. Inside it, call `initContentSdk` with whichever plugins you need. The following example implements a custom browser analytics provider:

```ts
import { Injectable, inject } from '@angular/core';
import { initContentSdk } from '@sitecore-content-sdk/core';
import { analyticsBrowserAdapter, analyticsPlugin } from '@sitecore-content-sdk/analytics-core'; // you can also implement your own
import { personalizeBrowserAdapter, personalizeBrowserPlugin, personalize, PersonalizeData } from '@sitecore-content-sdk/personalize'; // you can also implement your own
import { event, eventsPlugin, form, identity, pageView } from '@sitecore-content-sdk/events'; // for plugins, implement additional ones or import them
import type { EventData, IdentityData, PageViewData } from '@sitecore-content-sdk/events';
import { SITECORE_CONFIG_TOKEN, type SitecoreAnalyticsWrapper } from '@sitecore-content-sdk/angular';

@Injectable()
export class CustomBrowserAnalytics implements SitecoreAnalyticsWrapper {
  private readonly config = inject(SITECORE_CONFIG_TOKEN);
  private initPromise?: Promise<void>;
  private init(): Promise<void> {
    this.initPromise ??= initContentSdk({
      config: {
        contextId: this.config?.api?.edge?.clientContextId ?? '',
        edgeUrl: this.config?.api?.edge?.edgeUrl,
        siteName: this.config?.defaultSite ?? '',
      },
      plugins: [
        analyticsPlugin({
          options: { enableCookie: true, cookieExpiryDays: 30 },
          adapter: analyticsBrowserAdapter(),
        }),
        personalizeBrowserPlugin({
            adapter: personalizeBrowserAdapter(),
        }),
        eventsPlugin(),
        
      ],
    });
    return this.initPromise;
  }
  
  async pageView(data: PageViewData): Promise<void> {
    await this.init();
    await pageView(data);
  }

  async event(data: EventData): Promise<void> {
    await this.init();
    await event(data);
  }

  async identity(data: IdentityData): Promise<void> {
    await this.init();
    await identity(data);
  }

  async personalize(personalizeData: PersonalizeData): Promise<void> {
    await this.init();
    await personalize(personalizeData);
  }

  async form(
    formId: string,
    interactionType: 'VIEWED' | 'SUBMITTED',
    componentInstanceId: string
  ): Promise<void> {
    await this.init();
    await form(formId, interactionType, componentInstanceId);
  }
}
```

### Register it after `provideSitecoreAngular()`

The default Content SDK analytics provider uses a factory that injects a provider with server or browser plugins, depending on the environment. If you implement custom behavior per environment, use a factory too:

```ts
// src/app/app.config.ts
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

export const appConfig: ApplicationConfig = {
  providers: [
    provideSitecoreAngular({
      sitecoreConfig: scConfig,
      sitecoreClient: getClient(),
    }),
    // Overrides the analytics implementation registered above.
    { provide: SITECORE_ANALYTICS,useFactory: () =>
      isPlatformBrowser(inject(PLATFORM_ID))
        ? new CustomBrowserAnalytics()
        : new CustomServerAnalytics()
    },
  ],
};
```

Order matters. Registering your provider before `provideSitecoreAngular()` has no effect, because the SDK's own provider is registered afterwards and takes precedence.

You can also decide whether to use browser or server plugins inside the custom provider implementation itself. In that case, you don't need `useFactory`, and a single implementation can be injected in both environments.

## Registering additional plugins and adapters

The `plugins` array you pass to `initContentSdk` is where you extend the runtime. Each plugin can carry its own adapter, so a plugin list with three plugins can carry three adapters — one per capability, each matched to the environment the code runs in.

The Content SDK ships two adapter families:

| Adapter family | Interface | Provides | Implementations |
| --- | --- | --- | --- |
| Analytics | `AnalyticsAdapter` | Client ID handling, bot detection, URL search params | `analyticsBrowserAdapter()`, `analyticsServerAdapter(req, res)` |
| Personalize | `PersonalizeAdapter` | Profile ID handling, user agent | `personalizeBrowserAdapter()`, `personalizeServerAdapter(req, res)` |

### Adding personalization in the browser

The following example adds `personalizeBrowserPlugin()` to the browser plugin list. It carries the personalize browser adapter, while the analytics plugin keeps its own:

```ts
// src/content-sdk/analytics/custom-analytics.ts
import { analyticsBrowserAdapter, analyticsPlugin } from '@sitecore-content-sdk/analytics-core';
import { eventsPlugin } from '@sitecore-content-sdk/events';
import {
  personalizeBrowserAdapter,
  personalizeBrowserPlugin,
} from '@sitecore-content-sdk/personalize';

await initContentSdk({
  config: { contextId, edgeUrl, siteName },
  plugins: [
    analyticsPlugin({
      options: { enableCookie: true, cookieDomain: normalizeCookieDomain(location.hostname) },
      adapter: analyticsBrowserAdapter(),
    }),
    eventsPlugin(),
    personalizeBrowserPlugin({
      adapter: personalizeBrowserAdapter(),
      options: {
        enablePersonalizeCookie: true,
        webPersonalization: { async: true, defer: false },
      },
    }),
  ],
});
```

`webPersonalization` loads the Sitecore web personalization script in the browser. Pass `true` to use the defaults, or an object to control the `async`, `defer`, and `language` attributes. This option only applies in the browser.

## Package dependencies

`@sitecore-content-sdk/analytics-core`, `@sitecore-content-sdk/events`, and `@sitecore-content-sdk/personalize` are peer dependencies of `@sitecore-content-sdk/angular`, so they are already installed and importable. To call `initContentSdk` directly, add the core package to your application:

```shell
npm install @sitecore-content-sdk/core
```

## Overriding plugins in the Express middleware

The bot tracking and personalization middleware run outside the Angular injector, so DI does not apply to them. Their plugin sets are fixed, but you can configure their behavior through options: `matcher` and `skip` on both, and `personalizeService`, `getExtraUtmParams`, `extractGeoDataCb`, and `skipForBot` on personalization. If you need a different plugin set on the server, write your own Express middleware that calls `initContentSdk`, and register it in place of the built-in one.
