# Track custom events on web
> Track self-describing events and attach custom entities using JSON schemas for flexible data capture.
> Source: https://docs.snowplow.io/docs/sources/web-trackers/custom-tracking-using-schemas/
> Documentation index: https://docs.snowplow.io/llms.txt

The specific data you need might not be covered by the JavaScript tracker's built-in event types and entities. In this case, you can use Snowplow’s [self-describing events](/docs/fundamentals/events/#self-describing-events) and custom [entities](/docs/fundamentals/entities/) to track [customized data](/docs/events/custom-events/).

> **Note: Before you start: create the schema**
>
> Each self-describing event and custom entity needs a schema in your account before you track it. See [managing data structures](/docs/event-studio/data-structures/) to create one in Console.

## Track a custom event (self-describing)

To track a custom self-describing event, use the `trackSelfDescribingEvent` method. For example:

**JavaScript (tag):**

```javascript
snowplow('trackSelfDescribingEvent', {
  event: {
    schema: 'iglu:com.acme_company/viewed_product/jsonschema/1-0-0',
    data: {
        productId: 'ASO01043',
        category: 'Dresses',
        brand: 'ACME',
        returning: true,
        price: 49.95,
        sizes: ['xs', 's', 'l', 'xl', 'xxl'],
        availableSince: new Date(2013,3,7)
    }
  }
});
```

**Browser (npm):**

```javascript
import { trackSelfDescribingEvent } from '@snowplow/browser-tracker';

trackSelfDescribingEvent({
  event: {
    schema: 'iglu:com.acme_company/viewed_product/jsonschema/1-0-0',
    data: {
        productId: 'ASO01043',
        category: 'Dresses',
        brand: 'ACME',
        returning: true,
        price: 49.95,
        sizes: ['xs', 's', 'l', 'xl', 'xxl'],
        availableSince: new Date(2013,3,7)
    }
  }
});
```

***

The second argument or event property, depending on tracker, is a [self-describing JSON](http://snowplowanalytics.com/blog/2014/05/15/introducing-self-describing-jsons/). It has two fields:

- A `data` field, containing the properties of the event
- A `schema` field, containing the location of the [JSON schema](http://json-schema.org/) against which the `data` field should be validated.

Like all `trackX` methods, `trackSelfDescribingEvent` can also be passed an array of custom entities as an additional parameter.

## Track a custom entity

Custom [entities](/docs/fundamentals/entities/) can be used to augment any standard Snowplow event type, including self-describing events, with additional data.

The context is an array of entities. More than one entity (of either different or the same type) can be attached to an event. The `context` argument (if it is provided at all) should be a non-empty array.

As with self-describing events, if you want to create your own custom entities, you will need to [create a corresponding schema](/docs/event-studio/data-structures/). Snowplow uses the schema to validate that the JSON containing the entity properties is well-formed.

> **Tip:** Custom entities can be added as an extra argument to most Snowplow's `trackX()` methods, e.g. `trackPageView` or `trackLinkClick`.
>
> Not all plugins support adding custom entities; please refer to the corresponding plugin documentation for details.

Here are two examples of schema for custom entities. One describes a screen:

```json
{
    "$schema": "http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#",
    "self": {
        "vendor": "com.example",
        "name": "screen",
        "format": "jsonschema",
        "version": "1-0-1"
    },
    "type": "object",
    "properties": {
        "screenType": {
            "type": "string"
        },
        "lastUpdated": {
            "type": "string"
        }
    }
    "required": ["screenType", "lastUpdated"],
    "additionalProperties": false
}
```

and the other describes a user on that screen:

```json
{
    "$schema": "http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#",
    "self": {
        "vendor": "com.example",
        "name": "user",
        "format": "jsonschema",
        "version": "2-0-0"
    },
    "type": "object",
    "properties": {
        "user": {
            "type": "string"
        }
    }
    "required": ["user"],
    "additionalProperties": false
}
```

**Important:** Even if only one custom entity is being attached to an event, it still needs to be wrapped in an array.

Tracking a **page view** with both of these example entities attached:

**JavaScript (tag):**

```javascript
snowplow('trackPageView', {
  context: [{
    schema: "iglu:com.example_company/page/jsonschema/1-2-1",
    data: {
      pageType: 'test',
      lastUpdated: new Date(2021,04,01)
    }
  },
  {
    schema: "iglu:com.example_company/user/jsonschema/2-0-0",
    data: {
      userType: 'tester'
    }
  }]
});
```

**Browser (npm):**

```javascript
trackPageView({
  context: [{
    schema: 'iglu:com.example_company/page/jsonschema/1-2-1',
    data: {
      pageType: 'test',
      lastUpdated: new Date(2021,04,01)
    }
  },
  {
    schema: 'iglu:com.example_company/user/jsonschema/2-0-0',
    data: {
      userType: 'tester'
    }
  }]
});
```

***

Tracking a **self describing event** with both of these entities attached:

**JavaScript (tag):**

```javascript
snowplow('trackSelfDescribingEvent', {
  event: {
    schema: 'iglu:com.example_company/product_viewed/jsonschema/1-0-1',
    data: {
      productId: '12345',
      price: 10.99
    }
  },
  context: [{
    schema: 'iglu:com.example_company/page/jsonschema/1-2-1',
    data: {
      pageType: 'test',
      lastUpdated: new Date(2021,04,01)
    }
  },
  {
    schema: "iglu:com.example_company/user/jsonschema/2-0-0",
    data: {
      userType: 'tester'
    }
  }]
});
```

**Browser (npm):**

```javascript
trackSelfDescribingEvent({
  event: {
    schema: 'iglu:com.example_company/product_viewed/jsonschema/1-0-1',
    data: {
      productId: '12345',
      price: 10.99
    }
  },
  context: [{
    schema: 'iglu:com.example_company/page/jsonschema/1-2-1',
    data: {
      pageType: 'test',
      lastUpdated: new Date(2021,04,01)
    }
  },
  {
    schema: "iglu:com.example_company/user/jsonschema/2-0-0",
    data: {
      userType: 'tester'
    }
  }]
});
```

***

## Track a structured event

We recommend using custom self-describing events instead of structured events, as the provide more better data governance and easier modeling.

There are five parameters that can be associated with each structured event. Only the first two are required:

| Name       | Required? | Description                                                                                                                                                      | Type    |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `Category` | Yes       | The name you supply for the group of objects you want to track e.g. 'media', 'ecomm'.                                                                            | String  |
| `Action`   | Yes       | Defines the type of user interaction for the web object e.g. 'play-video', add-to-basket'.                                                                       | String  |
| `Label`    | No        | Identifies the specific object being actioned e.g. ID of the video being played, or the SKU or the product added to basket.                                      | String? |
| `Property` | No        | Describing the object or the action performed on it. This might be the quantity of an item added to basket.                                                      | String? |
| `Value`    | No        | Quantify or further describe the user action. This might be the price of an item added to basket, or the starting time of the video where play was just pressed. | Float?  |

An example of tracking a user listening to a music mix:

**JavaScript (tag):**

```javascript
snowplow('trackStructEvent', {
  category: 'Mixes',
  action: 'Play',
  label: 'MrC/fabric-0503-mix',
  property: '',
  value: 0.0
});
```

**Browser (npm):**

```javascript
import { trackStructEvent } from '@snowplow/browser-tracker';

trackStructEvent({
  category: 'Mixes',
  action: 'Play',
  label: 'MrC/fabric-0503-mix',
  value: 0.0
});
```

***
