How to Create an Analytics Module Provider

In this document, you’ll learn how to create an Analytics Module Provider and the methods you must implement in its main service.


Implementation Example#

As you implement your Analytics Module Provider, it can be useful to refer to an existing provider and how it's implemeted.

If you need to refer to an existing implementation as an example, check the PostHog Analytics Module Provider in the Medusa repository.


Create Module Provider Directory#

Start by creating a new directory for your module provider.

If you're creating the module provider in a Medusa application, create it under the src/modules directory. For example, src/modules/my-analytics.

If you're creating the module provider in a plugin, create it under the src/providers directory. For example, src/providers/my-analytics.

Note: The rest of this guide always uses the src/modules/my-analytics directory as an example.

2. Create the Analytics Module Provider's Service#

Create the file src/modules/my-analytics/service.ts that holds the implementation of the module provider's main service. It must extend the AbstractAnalyticsProviderService class imported from @medusajs/framework/utils:

src/modules/my-analytics/service.ts
1import { AbstractAnalyticsProviderService } from "@medusajs/framework/utils"2
3class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {4  // TODO implement methods5}6
7export default MyAnalyticsProviderService

constructor#

The constructor allows you to access resources from the module's container using the first parameter, and the module's options using the second parameter.

If you're creating a client or establishing a connection with a third-party service, do it in the constructor.

Example

Code
1import { Logger } from "@medusajs/framework/types"2import { AbstractAnalyticsProviderService } from "@medusajs/framework/utils"3
4type InjectedDependencies = {5  logger: Logger6}7
8type Options = {9  apiKey: string10}11
12class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {13  protected logger_: Logger14  protected options_: Options15  static identifier = "my-analytics"16  // assuming you're initializing a client17  protected client18
19  constructor (20    { logger }: InjectedDependencies,21    options: Options22  ) {23    super()24
25    this.logger_ = logger26    this.options_ = options27
28    // assuming you're initializing a client29    this.client = new Client(options)30  }31}32
33export default MyAnalyticsProviderService

identifier#

Each analytics provider has a unique ID used to identify it. The provider's ID will be stored as aly_{identifier}_{id}, where {id} is the provider's id property in the medusa-config.ts.

Example

Code
1class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {2  static identifier = "my-analytics"3  // ...4}

identify#

This method identifies an actor or group in the third-party analytics provider. The Analytics Module will use this method in its identify method if your provider is configured in medusa-config.ts.

Example

Code
1class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {2  // ...3  async identify(4    data: ProviderIdentifyAnalyticsEventDTO5  ): Promise<void> {6    // identify actor or group in the analytics provider7    // or using custom logic8    // for example:9    this.client.identify(data)10  }11}

Parameters

The details of the actor or group.

Returns

PromisePromise<void>
Resolves when the actor or group is identified successfully.

shutdown#

optional

This method is used to shutdown the analytics provider, and flush all data before shutting down.

This method is called by the Analytics Module when the Medusa application is shutting down.

Example

Code
1class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {2  // ...3  async shutdown(): Promise<void> {4    // perform any cleanup or shutdown logic5    // in the analytics provider or using custom logic6    // for example:7    await this.client.shutdown()8  }9}

Returns

PromisePromise<void>
Resolves when the provider is shutdown successfully.

track#

This method tracks an event with the third-party analytics provider. The Analytics Module will use this method in its track method if your provider is configured in medusa-config.ts.

You can send the event to the third-party provider based on its semantics.

Example

Code
1class MyAnalyticsProviderService extends AbstractAnalyticsProviderService {2  // ...3  async track(4    data: ProviderTrackAnalyticsEventDTO5  ): Promise<void> {6    // track event to third-party provider7    // or using custom logic8    // for example:9    this.client.track(data)10  }11}

Parameters

The event's details.

Returns

PromisePromise<void>
Resolves when the event is tracked successfully.

3. Create Module Provider Definition File#

Create the file src/modules/my-analytics/index.ts with the following content:

src/modules/my-analytics/index.ts
1import MyAnalyticsProviderService from "./service"2import { 3  ModuleProvider, 4  Modules5} from "@medusajs/framework/utils"6
7export default ModuleProvider(Modules.ANALYTICS, {8  services: [MyAnalyticsProviderService],9})

This exports the module provider's definition, indicating that the MyAnalyticsProviderService is the module provider's service.


4. Use Module Provider#

To use your Analytics Module Provider, add it to the providers array of the Analytics Module in medusa-config.ts:

Note: The Analytics Module accepts one provider only.
medusa-config.ts
1module.exports = defineConfig({2  // ...3  modules: [4    {5      resolve: "@medusajs/medusa/analytics",6      options: {7        providers: [8          {9            // if module provider is in a plugin, use `plugin-name/providers/my-analytics`10            resolve: "./src/modules/my-analytics",11            id: "my-analytics",12            options: {13              // provider options...14            },15          },16        ],17      },18    },19  ]20})

5. Test it Out#

To test the module out, you'll track in your third-party provider when an order is placed.

You'll first create a workflow that tracks the order completion event. Then, you can execute the workflow in a subscriber that listens to the order.placed event.

For example, create a workflow at src/workflows/track-order-placed.ts with the following content:

src/workflows/track-order-created.ts
1import { createWorkflow } from "@medusajs/framework/workflows-sdk"2import { createStep } from "@medusajs/framework/workflows-sdk"3import { Modules } from "@medusajs/framework/utils"4import { OrderDTO } from "@medusajs/framework/types"5
6type StepInput = {7  order: OrderDTO8}9
10const trackOrderCreatedStep = createStep(11  "track-order-created-step",12  async ({ order }: StepInput, { container }) => {13    const analyticsModuleService = container.resolve(Modules.ANALYTICS)14
15    await analyticsModuleService.track({16      event: "order_created",17      userId: order.customer_id,18      properties: {19        order_id: order.id,20        total: order.total,21        items: order.items.map((item) => ({22          variant_id: item.variant_id,23          product_id: item.product_id,24          quantity: item.quantity,25        })),26        customer_id: order.customer_id,27      },28    })29  }30)31
32type WorkflowInput = {33  order_id: string34}35
36export const trackOrderCreatedWorkflow = createWorkflow(37  "track-order-created-workflow",38  ({ order_id }: WorkflowInput) => {39    const { data: orders } = useQueryGraphStep({40      entity: "order",41      fields: [42        "*",43        "customer.*",44        "items.*"45      ],46      filters: {47        id: order_id,48      },49    })50    trackOrderCreatedStep({51      order: orders[0],52    })53  }54)

This workflow retrieves the order details using the useQueryGraphStep and then tracks the order creation event using the trackOrderCreatedStep.

In the step, you resolve the service of the Analytics Module from the Medusa container and use its track method to track the event. This method will use the underlying provider configured (which is your provider, in this case) to track the event.

Next, create a subscriber at src/subscribers/order-placed.ts with the following content:

src/subscribers/order-placed.ts
1import type {2  SubscriberArgs,3  SubscriberConfig,4} from "@medusajs/framework"5import { trackOrderCreatedWorkflow } from "../workflows/track-order-created"6
7export default async function orderPlacedHandler({8  event: { data },9  container,10}: SubscriberArgs<{ id: string }>) {11  await trackOrderCreatedWorkflow(container).run({12    input: {13      order_id: data.id,14    },15  })16}17
18export const config: SubscriberConfig = {19  event: "order.placed",20}

This subscriber listens to the order.placed event and executes the trackOrderCreatedWorkflow workflow, passing the order ID as input.

You'll now track the order creation event whenever an order is placed in your Medusa application. You can test this out by placing an order and checking in your third-party provider if the event was tracked successfully.


Additional Resources#

Was this page helpful?
Ask Anything
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break