diff --git a/packages/plugin-custom-enrichment-browser/CHANGELOG.md b/packages/plugin-custom-enrichment-browser/CHANGELOG.md
new file mode 100644
index 000000000..fa4d35e68
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/CHANGELOG.md
@@ -0,0 +1 @@
+# Change Log
\ No newline at end of file
diff --git a/packages/plugin-custom-enrichment-browser/README.md b/packages/plugin-custom-enrichment-browser/README.md
new file mode 100644
index 000000000..31eb824ef
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/README.md
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+# @amplitude/plugin-custom-enrichment-browser
+
+Official Browser SDK plugin for custom enrichment
+
+## Installation
+
+This package is published on NPM registry and is available to be installed using npm and yarn.
+
+```sh
+# npm
+npm install @amplitude/plugin-custom-enrichment-browser
+
+# yarn
+yarn add @amplitude/plugin-custom-enrichment-browser
+```
+
+## Usage
+
+This plugin works on top of Amplitude Browser SDK and allows the user to execute custom functionality on their events. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.0.0` or later.
+
+### 1. Import Amplitude packages
+
+* `@amplitude/plugin-custom-enrichment-browser`
+
+```typescript
+import { customEnrichmentPlugin } from '@amplitude/plugin-custom-enrichment-browser';
+```
+
+### 2. Instantiate custom enrichment plugin
+```typescript
+const customEnrichmentPlugin = customEnrichmentPlugin();
+```
+
+#### Options
+
+
+### 3. Install plugin to Amplitude SDK
+
+```typescript
+amplitude.add(customEnrichmentPlugin);
+```
+
+### 4. Initialize Amplitude SDK
+
+```typescript
+amplitude.init('API_KEY');
+```
+
+## Result
+This plugin executes a user-defined script, defined within Amplitude Remote Configuration Settings.
+
+#### Event type
+* No event type added
+
+#### Event properties
+* Defined by user
\ No newline at end of file
diff --git a/packages/plugin-custom-enrichment-browser/jest.config.js b/packages/plugin-custom-enrichment-browser/jest.config.js
new file mode 100644
index 000000000..dc4094b18
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/jest.config.js
@@ -0,0 +1,10 @@
+const baseConfig = require('../../jest.config.js');
+const package = require('./package');
+
+module.exports = {
+ ...baseConfig,
+ displayName: package.name,
+ rootDir: '.',
+ testEnvironment: 'jsdom',
+ coveragePathIgnorePatterns: ['index.ts'],
+};
diff --git a/packages/plugin-custom-enrichment-browser/package.json b/packages/plugin-custom-enrichment-browser/package.json
new file mode 100644
index 000000000..81536df59
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@amplitude/plugin-custom-enrichment-browser",
+ "private": true,
+ "version": "0.0.1",
+ "description": "",
+ "author": "Amplitude Inc",
+ "homepage": "https://github.com/amplitude/Amplitude-TypeScript",
+ "license": "MIT",
+ "main": "lib/cjs/index.js",
+ "module": "lib/esm/index.js",
+ "types": "lib/esm/index.d.ts",
+ "sideEffects": false,
+ "publishConfig": {
+ "access": "public",
+ "tag": "latest"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/amplitude/Amplitude-TypeScript.git"
+ },
+ "scripts": {
+ "build": "yarn bundle && yarn build:es5 && yarn build:esm",
+ "bundle": "rollup --config rollup.config.js",
+ "build:es5": "tsc -p ./tsconfig.es5.json",
+ "build:esm": "tsc -p ./tsconfig.esm.json",
+ "watch": "tsc -p ./tsconfig.esm.json --watch",
+ "clean": "rimraf node_modules lib coverage",
+ "fix": "yarn fix:eslint & yarn fix:prettier",
+ "fix:eslint": "eslint '{src,test}/**/*.ts' --fix",
+ "fix:prettier": "prettier --write \"{src,test}/**/*.ts\"",
+ "lint": "yarn lint:eslint & yarn lint:prettier",
+ "lint:eslint": "eslint '{src,test}/**/*.ts'",
+ "lint:prettier": "prettier --check \"{src,test}/**/*.ts\"",
+ "test": "jest",
+ "typecheck": "tsc -p ./tsconfig.json"
+ },
+ "bugs": {
+ "url": "https://github.com/amplitude/Amplitude-TypeScript/issues"
+ },
+ "dependencies": {
+ "@amplitude/analytics-core": "^2.27.0",
+ "tslib": "^2.4.1"
+
+ },
+ "devDependencies": {
+
+ },
+ "files": [
+ "lib"
+ ]
+}
diff --git a/packages/plugin-custom-enrichment-browser/rollup.config.js b/packages/plugin-custom-enrichment-browser/rollup.config.js
new file mode 100644
index 000000000..2718b91d7
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/rollup.config.js
@@ -0,0 +1,3 @@
+import { umd } from '../../scripts/build/rollup.config';
+
+export default [umd];
diff --git a/packages/plugin-custom-enrichment-browser/src/custom-enrichment.ts b/packages/plugin-custom-enrichment-browser/src/custom-enrichment.ts
new file mode 100644
index 000000000..7d6fb7fa2
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/src/custom-enrichment.ts
@@ -0,0 +1,53 @@
+import type { BrowserClient, BrowserConfig, EnrichmentPlugin, Event, ILogger } from '@amplitude/analytics-core';
+
+export const customEnrichmentPlugin = (): EnrichmentPlugin => {
+ let loggerProvider: ILogger | undefined = undefined;
+ let customEnrichmentBody: string | undefined = undefined;
+
+ const plugin: EnrichmentPlugin = {
+ name: '@amplitude/plugin-custom-enrichment-browser',
+ type: 'enrichment',
+
+ setup: async (config: BrowserConfig, _: BrowserClient) => {
+ loggerProvider = config.loggerProvider;
+ loggerProvider?.log('Installing @amplitude/plugin-custom-enrichment-browser');
+
+ // Fetch remote config for custom enrichment in a non-blocking manner
+ if (config.fetchRemoteConfig) {
+ if (!config.remoteConfigClient) {
+ // TODO(xinyi): Diagnostics.recordEvent
+ config.loggerProvider.debug('Remote config client is not provided, skipping remote config fetch');
+ } else {
+ config.remoteConfigClient.subscribe('analyticsSDK.customEnrichment', 'all', (remoteConfig) => {
+ if (remoteConfig) {
+ customEnrichmentBody = remoteConfig.body as string | undefined;
+ }
+ });
+ }
+ }
+ },
+ execute: async (event: Event) => {
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-implied-eval
+ const enrichEvent = new Function('event', customEnrichmentBody || '') as (event: Event) => Event;
+
+ const enrichedEvent: Event = enrichEvent(event);
+
+ if (!enrichedEvent) {
+ return event;
+ }
+
+ return enrichedEvent;
+ } catch (error) {
+ loggerProvider?.error('Could not execute custom enrichment function', error);
+ }
+
+ return event;
+ },
+ teardown: async () => {
+ // No teardown required
+ },
+ };
+
+ return plugin;
+};
diff --git a/packages/plugin-custom-enrichment-browser/src/index.ts b/packages/plugin-custom-enrichment-browser/src/index.ts
new file mode 100644
index 000000000..0eb16820f
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/src/index.ts
@@ -0,0 +1,2 @@
+export { customEnrichmentPlugin } from './custom-enrichment';
+export { customEnrichmentPlugin as plugin } from './custom-enrichment';
diff --git a/packages/plugin-custom-enrichment-browser/test/custom-enrichment.test.ts b/packages/plugin-custom-enrichment-browser/test/custom-enrichment.test.ts
new file mode 100644
index 000000000..1a3f8a738
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/test/custom-enrichment.test.ts
@@ -0,0 +1,462 @@
+import { type BrowserClient, type BrowserConfig, type ILogger, Logger, LogLevel } from '@amplitude/analytics-core';
+import { customEnrichmentPlugin } from '../src/custom-enrichment';
+
+// Mock BrowserClient implementation
+const createMockBrowserClient = (): jest.Mocked => {
+ const mockClient = {
+ init: jest.fn().mockReturnValue({
+ promise: Promise.resolve(),
+ }),
+ add: jest.fn(),
+ remove: jest.fn(),
+ track: jest.fn(),
+ logEvent: jest.fn(),
+ identify: jest.fn(),
+ groupIdentify: jest.fn(),
+ setGroup: jest.fn(),
+ revenue: jest.fn(),
+ flush: jest.fn(),
+ getUserId: jest.fn(),
+ setUserId: jest.fn(),
+ getDeviceId: jest.fn(),
+ setDeviceId: jest.fn(),
+ getSessionId: jest.fn(),
+ setSessionId: jest.fn(),
+ extendSession: jest.fn(),
+ reset: jest.fn(),
+ setOptOut: jest.fn(),
+ setTransport: jest.fn(),
+ } as unknown as jest.Mocked;
+
+ mockClient.track.mockReturnValue({
+ promise: Promise.resolve({
+ code: 200,
+ message: '',
+ event: {
+ event_type: 'test-event',
+ },
+ }),
+ });
+
+ return mockClient;
+};
+
+const createMockConfig = (): BrowserConfig => ({
+ apiKey: 'test-api-key',
+ flushQueueSize: 10,
+ flushIntervalMillis: 1000,
+ logLevel: LogLevel.Verbose,
+ loggerProvider: new Logger(),
+ sessionTimeout: 30000,
+ flushMaxRetries: 5,
+ optOut: false,
+ useBatch: false,
+ fetchRemoteConfig: false,
+ trackingOptions: {
+ ipAddress: true,
+ language: true,
+ platform: true,
+ },
+ cookieStorage: {
+ isEnabled: jest.fn().mockReturnValue(true),
+ get: jest.fn(),
+ set: jest.fn(),
+ remove: jest.fn(),
+ reset: jest.fn(),
+ getRaw: jest.fn(),
+ },
+ storageProvider: {
+ isEnabled: jest.fn().mockReturnValue(true),
+ get: jest.fn(),
+ set: jest.fn(),
+ remove: jest.fn(),
+ reset: jest.fn(),
+ getRaw: jest.fn(),
+ },
+ transportProvider: {
+ send: jest.fn(),
+ },
+});
+
+describe('Custom Enrichment Plugin', () => {
+ let mockClient: jest.Mocked;
+ let mockConfig: BrowserConfig;
+ let mockLogger: ILogger;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockClient = createMockBrowserClient();
+ mockConfig = createMockConfig();
+ mockLogger = {
+ log: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ debug: jest.fn(),
+ logLevel: LogLevel.Verbose,
+ disable: jest.fn(),
+ enable: jest.fn(),
+ } as ILogger;
+ mockConfig.loggerProvider = mockLogger;
+ });
+ describe('execute', () => {
+ it('should execute custom enrichment function successfully', async () => {
+ const customFunction = `
+ event.event_properties = event.event_properties || {};
+ event.event_properties.custom_field = 'enriched_value';
+ return event;
+ `;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the custom function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: customFunction });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = {
+ event_type: 'test_event',
+ event_properties: { original: 'value' },
+ };
+
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result).toEqual({
+ event_type: 'test_event',
+ event_properties: {
+ original: 'value',
+ custom_field: 'enriched_value',
+ },
+ });
+ });
+
+ it('should handle enrichment function that adds or modifies the event', async () => {
+ const timestamp = Date.now();
+ const customFunction = `
+ event.user_properties = { custom_user_prop: 'user_value' };
+ event.event_properties = { ...event.event_properties, timestamp: ${timestamp} };
+ event.event_type = 'enriched_event';
+ return event;
+ `;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the custom function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: customFunction });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = {
+ event_type: 'test_event',
+ event_properties: { test: 'value' },
+ };
+
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result?.event_type).toBe('enriched_event');
+ expect(result?.event_properties).toStrictEqual({ test: 'value', timestamp: timestamp });
+ expect(result?.user_properties).toStrictEqual({ custom_user_prop: 'user_value' });
+ });
+
+ it('should return original event if enrichment function throws error', async () => {
+ const invalidFunction = `
+ throw new Error('Invalid enrichment function');
+ `;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the invalid function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: invalidFunction });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result).toEqual(originalEvent);
+ expect((mockLogger.error as jest.Mock).mock.calls.length).toBe(1);
+ expect((mockLogger.error as jest.Mock).mock.calls[0][0]).toBe('Could not execute custom enrichment function');
+ });
+
+ it('should handle undefined loggerProvider in execute error case', async () => {
+ const configWithoutLogger = { ...mockConfig, loggerProvider: undefined as unknown as Logger } as BrowserConfig;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the error function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: 'throw new Error("test error");' });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...configWithoutLogger,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ // Should return original event even with undefined loggerProvider
+ expect(result).toEqual(originalEvent);
+ });
+
+ it('should return original event if enrichment function is invalid', async () => {
+ const invalidFunction = 'invalid javascript syntax {';
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the invalid function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: invalidFunction });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result).toEqual(originalEvent);
+ expect((mockLogger.error as jest.Mock).mock.calls.length).toBe(1);
+ expect((mockLogger.error as jest.Mock).mock.calls[0][0]).toBe('Could not execute custom enrichment function');
+ });
+
+ it('should return original event if enrichment function does not return an event', async () => {
+ const customFunction = `
+ // Function that doesn't return anything
+ event.event_properties = { modified: true };
+ `;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the custom function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: customFunction });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ // Should return the original event since the function didn't return anything
+ expect(result).toEqual(originalEvent);
+ });
+
+ it('should handle empty enrichment function', async () => {
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide empty function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: '' });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result).toEqual(originalEvent);
+ });
+
+ it('should handle enrichment function with only comments', async () => {
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide comment-only function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: '// This is just a comment' });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ expect(result).toEqual(originalEvent);
+ });
+ });
+
+ describe('remote config integration', () => {
+ it('should handle missing remote config client', async () => {
+ const plugin = customEnrichmentPlugin();
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: undefined,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ // Should return original event when no remote config is available
+ expect(result).toEqual(originalEvent);
+ expect((mockLogger.debug as jest.Mock).mock.calls.length).toBe(1);
+ expect((mockLogger.debug as jest.Mock).mock.calls[0][0]).toBe(
+ 'Remote config client is not provided, skipping remote config fetch',
+ );
+ });
+
+ it('should handle fetchRemoteConfig disabled', async () => {
+ const plugin = customEnrichmentPlugin();
+
+ const configWithoutRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: false,
+ };
+
+ await plugin.setup?.(configWithoutRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ // Should return original event when remote config is disabled
+ expect(result).toEqual(originalEvent);
+ });
+
+ it('should handle remote config subscription', async () => {
+ const plugin = customEnrichmentPlugin();
+
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn(),
+ };
+
+ const configWithRemoteConfig = {
+ ...mockConfig,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ // Verify that subscribe was called with the correct parameters
+ expect(mockRemoteConfigClient.subscribe).toHaveBeenCalled();
+ expect(mockRemoteConfigClient.subscribe.mock.calls[0][0]).toBe('analyticsSDK.customEnrichment');
+ expect(mockRemoteConfigClient.subscribe.mock.calls[0][1]).toBe('all');
+ expect(typeof mockRemoteConfigClient.subscribe.mock.calls[0][2]).toBe('function');
+ });
+ });
+
+ describe('teardown', () => {
+ it('should complete teardown without errors', async () => {
+ const plugin = customEnrichmentPlugin();
+ await plugin.setup?.(mockConfig, mockClient);
+ await expect(plugin.teardown?.()).resolves.toBeUndefined();
+ });
+ });
+
+ describe('undefined loggerProvider', () => {
+ it('should handle undefined loggerProvider in setup', async () => {
+ const configWithoutLogger = { ...mockConfig, loggerProvider: undefined } as unknown as BrowserConfig;
+ const plugin = customEnrichmentPlugin();
+
+ // Should not throw an error even with undefined loggerProvider
+ await expect(plugin.setup?.(configWithoutLogger, mockClient)).resolves.toBeUndefined();
+ });
+
+ it('should handle undefined loggerProvider in execute error case', async () => {
+ const configWithoutLogger = { ...mockConfig, loggerProvider: undefined } as unknown as BrowserConfig;
+ const plugin = customEnrichmentPlugin();
+
+ // Mock remote config to provide the error function
+ const mockRemoteConfigClient = {
+ subscribe: jest.fn((key, _audience, callback) => {
+ if (key === 'analyticsSDK.customEnrichment') {
+ callback({ body: 'throw new Error("test error");' });
+ }
+ }),
+ };
+
+ const configWithRemoteConfig = {
+ ...configWithoutLogger,
+ fetchRemoteConfig: true,
+ remoteConfigClient: mockRemoteConfigClient,
+ };
+
+ await plugin.setup?.(configWithRemoteConfig, mockClient);
+
+ const originalEvent = { event_type: 'test_event' };
+ const result = await plugin.execute?.(originalEvent);
+
+ // Should return original event and not throw even with undefined loggerProvider
+ expect(result).toEqual(originalEvent);
+ });
+ });
+});
diff --git a/packages/plugin-custom-enrichment-browser/tsconfig.es5.json b/packages/plugin-custom-enrichment-browser/tsconfig.es5.json
new file mode 100644
index 000000000..77e041d3f
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/tsconfig.es5.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*"],
+ "compilerOptions": {
+ "module": "commonjs",
+ "noEmit": false,
+ "outDir": "lib/cjs",
+ "rootDir": "./src"
+ }
+}
diff --git a/packages/plugin-custom-enrichment-browser/tsconfig.esm.json b/packages/plugin-custom-enrichment-browser/tsconfig.esm.json
new file mode 100644
index 000000000..bec981eee
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/tsconfig.esm.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src/**/*"],
+ "compilerOptions": {
+ "module": "es6",
+ "noEmit": false,
+ "outDir": "lib/esm",
+ "rootDir": "./src"
+ }
+}
diff --git a/packages/plugin-custom-enrichment-browser/tsconfig.json b/packages/plugin-custom-enrichment-browser/tsconfig.json
new file mode 100644
index 000000000..955dcce78
--- /dev/null
+++ b/packages/plugin-custom-enrichment-browser/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": ["src/**/*", "test/**/*"],
+ "compilerOptions": {
+ "baseUrl": ".",
+ "esModuleInterop": true,
+ "lib": ["dom"],
+ "noEmit": true,
+ "rootDir": ".",
+ }
+}
diff --git a/packages/plugin-page-url-enrichment-browser/README.md b/packages/plugin-page-url-enrichment-browser/README.md
index c67aac345..a43792ce2 100644
--- a/packages/plugin-page-url-enrichment-browser/README.md
+++ b/packages/plugin-page-url-enrichment-browser/README.md
@@ -34,9 +34,6 @@ import { pageUrlEnrichmentPlugin } from '@amplitude/plugin-page-url-enrichment-b
```
### 2. Instantiate page url enrichment plugin
-
-The plugin accepts an optional parameter of type `Object` to configure the plugin based on your use case.
-
```typescript
const pageUrlEnrichment = pageUrlEnrichmentPlugin();
```