Skip to main content

Generate tracking code

Once you've installed and initialized Snowtype, you can generate tracking code from the sources you configured.

To generate tracking code, run:

bash
npx snowtype generate

When you run snowtype generate, Snowtype will produce a single output file, at the path set in your configuration file. The contents will vary based on the tracker and language you selected, but generally include:

  • Types, interfaces, or classes for each schema
  • Functions to track the schemas as self-describing events or entities
  • For event specifications, functions to track the events with the correct schemas and instructions defined in the specification

Snowtype will generate code for you to track all schemas as either a self-describing event or entity, regardless of how you've defined your data structures in Console.

The first time you run generate, Snowtype creates a .snowtype-lock.json file next to your configuration file. This pins the event specification versions used for generation, so subsequent runs produce consistent output. To check for newer event specification versions, use snowtype update.

The generated code isn't minified and includes inline documentation. You can modify it to suit your project, but any changes will be overwritten the next time you run generate.

The code expects the relevant Snowplow tracker to already be installed in your project. Snowtype doesn't install trackers for you.

Data structures

For data structures and Iglu Central schemas, Snowtype generates two functions: one to track the schema as a self-describing event, and one to create an entity object. It will also create whatever types or helper functions are available for the selected language.

See the Use the generated code section below for an example of how to use the generated functions in your code.

This example shows generated Browser tracker TypeScript code for the web_page schema from Iglu Central, and a custom product data structure. The inline comments are generated from the schema descriptions.

To see the output for different trackers and languages, check out the full examples page.

jsonsnowtype.config.json
{
"orgId": "your-org-id",
"tracker": "@snowplow/browser-tracker",
"language": "typescript",
"outpath": "./src/tracking/snowplow",
"dataProductIds": [],
"eventSpecificationIds": [],
"igluCentralSchemas": [
"iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0"
],
"dataStructures": [
"iglu:com.example/product/jsonschema/1-0-0"
]
}
tsxGenerated output
import { trackSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '@snowplow/browser-tracker';
// Automatically generated by Snowtype

/**
* Schema for a web page
*/
export type WebPage = {
/**
* The page view ID.
*/
id: string;
}

/**
* Schema for a product entity
*/
export type Product = {
/**
* The product category.
*/
category: string;
/**
* The currency the product is listed in.
*/
currency: string;
/**
* The product ID (SKU).
*/
id: string;
/**
* The product name.
*/
name: string;
/**
* The price of the product.
*/
price: number;
}

type ContextsOrTimestamp<T = any> = Omit<CommonEventProperties<T>, 'context'> & { context?: SelfDescribingJson<T>[] | null | undefined }
/**
* Track a Snowplow event for WebPage.
* Schema for a web page
*/
export function trackWebPage<T extends {} = any>(webPage: WebPage & ContextsOrTimestamp<T>, trackers?: string[]){
const { context, timestamp, ...data } = webPage;
const event: SelfDescribingJson = {
schema: 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0',
data
};

trackSelfDescribingEvent({
event,
context,
timestamp,
}, trackers);
}

/**
* Creates a Snowplow WebPage entity.
*/
export function createWebPage(webPage: WebPage){
return {
schema: 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0',
data: webPage
}
}
/**
* Track a Snowplow event for Product.
* Schema for a product entity
*/
export function trackProduct<T extends {} = any>(product: Product & ContextsOrTimestamp<T>, trackers?: string[]){
const { context, timestamp, ...data } = product;
const event: SelfDescribingJson = {
schema: 'iglu:com.example/product/jsonschema/1-0-0',
data
};

trackSelfDescribingEvent({
event,
context,
timestamp,
}, trackers);
}

/**
* Creates a Snowplow Product entity.
*/
export function createProduct(product: Product){
return {
schema: 'iglu:com.example/product/jsonschema/1-0-0',
data: product
}
}

Event specifications

For event specifications, which have more requirements and metadata than data structures or Iglu Central schemas, Snowtype generates additional code.

Along with the self-describing event and entity functions for each schema, it also produces a function to track the event according to the instructions defined in the specification. This includes any required entities, as well as an event specification entity that links this event to its tracking plan.

See the Use the generated code section below for an example of how to use the generated functions in your code. For JavaScript and TypeScript, the key function is called track{EventSpecificationName}Spec.

Event specification version

Changes to event specifications increases the version number. Your lockfile pins specific event specification versions.

If you don't see the expected changes in your generated code after editing the event specification, try running snowtype update.

This example shows generated Browser tracker TypeScript code for a User Log In event specification. The event specification has a login event data structure, plus two entities: user_authentication and user.

To see the output for different trackers and languages, check out the full examples page.

jsonsnowtype.config.json
{
"orgId": "your-org-id",
"tracker": "@snowplow/browser-tracker",
"language": "typescript",
"outpath": "./src/tracking/snowplow",
"dataProductIds": [],
"igluCentralSchemas": [],
"dataStructures": [],
"eventSpecificationIds": ["a965caf1-88a6-4a89-9aea-cc92516a9d56"]
}
tsxGenerated output
import { trackSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '@snowplow/browser-tracker';
// Automatically generated by Snowtype

/**
* Captured when a user attempts to log in to their account. Tracks the method and outcome
* of the authentication attempt.
*/
export type Login = {
/**
* An optional error code if the login attempt failed (e.g., 'invalid_password',
* 'user_not_found').
*/
error_code?: null | string;
/**
* Whether the login attempt was successful.
*/
is_success: boolean;
/**
* The method used to authenticate, such as 'email', 'google', 'apple', or 'saml'.
*/
method: string;
}

/**
* A subset of the user fields from the users-service
*/
export type User = {
/**
* The users access level.
*/
accessLevel?: AccessLevel;
/**
* The users email address.
*/
email?: null | string;
/**
* The users first name.
*/
firstName: string;
/**
* The users job title.
*/
jobTitle?: null | string;
/**
* The users last name.
*/
lastName: string;
/**
* The organization's UUID that the user belongs to.
*/
organizationId: string;
/**
* The users UUID.
*/
userId: string;
}

/**
* The users access level.
*/
export type AccessLevel = "Admin" | "User" | "Custom";

/**
* Data structure that defines how the user logged in
*/
export type UserAuthentication = {
/**
* Type of authentication used
*/
auth_type: AuthType;
}

/**
* Type of authentication used
*/
export type AuthType = "google" | "facebook" | "manual";

/**
* Creates a Snowplow Event Specification entity.
*/
export function createEventSpecification(eventSpecification: Omit<EventSpecification, 'data_product_domain'> & Partial<Pick<EventSpecification, 'data_product_domain'>>){
return {
schema:
'iglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-4',
data: eventSpecification,
}
}

/**
* Automatically attached context for event specifications
*/
interface EventSpecification {
id: string;
version: number;
name: string;
data_product_id: string;
data_product_name: string;
data_product_domain?: string;
}

type ContextsOrTimestamp<T = any> = Omit<CommonEventProperties<T>, 'context'> & { context?: SelfDescribingJson<T>[] | null | undefined }
/**
* Track a Snowplow event for Login.
* Captured when a user attempts to log in to their account. Tracks the method and outcome of the authentication attempt.
*/
export function trackLogin<T extends {} = any>(login: Login & ContextsOrTimestamp<T>, trackers?: string[]){
const { context, timestamp, ...data } = login;
const event: SelfDescribingJson = {
schema: 'iglu:com.snplow.msc.aws/login/jsonschema/1-0-0',
data
};

trackSelfDescribingEvent({
event,
context,
timestamp,
}, trackers);
}

/**
* Creates a Snowplow Login entity.
*/
export function createLogin(login: Login){
return {
schema: 'iglu:com.snplow.msc.aws/login/jsonschema/1-0-0',
data: login
}
}
/**
* Track a Snowplow event for User.
* A subset of the user fields from the users-service
*/
export function trackUser<T extends {} = any>(user: User & ContextsOrTimestamp<T>, trackers?: string[]){
const { context, timestamp, ...data } = user;
const event: SelfDescribingJson = {
schema: 'iglu:com.snowplowanalytics.console/user/jsonschema/1-0-1',
data
};

trackSelfDescribingEvent({
event,
context,
timestamp,
}, trackers);
}

/**
* Creates a Snowplow User entity.
*/
export function createUser(user: User){
return {
schema: 'iglu:com.snowplowanalytics.console/user/jsonschema/1-0-1',
data: user
}
}
/**
* Track a Snowplow event for UserAuthentication.
* Data structure that defines how the user logged in
*/
export function trackUserAuthentication<T extends {} = any>(userAuthentication: UserAuthentication & ContextsOrTimestamp<T>, trackers?: string[]){
const { context, timestamp, ...data } = userAuthentication;
const event: SelfDescribingJson = {
schema: 'iglu:com.snplow.msc.aws/user_authentication/jsonschema/1-0-0',
data
};

trackSelfDescribingEvent({
event,
context,
timestamp,
}, trackers);
}

/**
* Creates a Snowplow UserAuthentication entity.
*/
export function createUserAuthentication(userAuthentication: UserAuthentication){
return {
schema: 'iglu:com.snplow.msc.aws/user_authentication/jsonschema/1-0-0',
data: userAuthentication
}
}

/**
* Tracks a UserLogIn event specification.
* ID: a965caf1-88a6-4a89-9aea-cc92516a9d56
*/
export function trackUserLogInSpec(userLogIn: Login & ContextsOrTimestamp<User | UserAuthentication>, trackers?: string[]){
const eventSpecificationContext = createEventSpecification({
id: 'a965caf1-88a6-4a89-9aea-cc92516a9d56',
version: 8,
name: 'User Log In',
data_product_id: '57471841-aa79-445d-b4f7-1cbd073a3188',
data_product_name: 'Checkout Flow',
data_product_domain: 'Marketing'
});

const context = Array.isArray(userLogIn.context)
? [...userLogIn.context, eventSpecificationContext]
: [eventSpecificationContext];

const modifiedUserLogIn = {
...userLogIn,
context,
};

trackLogin<User | UserAuthentication | EventSpecification>(modifiedUserLogIn, trackers);
}

Event specification entity

Code generated for event specifications includes an entity that allows you to link the tracked event to its event specification and tracking plan.

event_specification

Entity
Entity schema for referencing an event specification
Schema URIiglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-4
Example
json
{
"id": "a965caf1-88a6-4a89-9aea-cc92516a9d56",
"name": "User Log In",
"data_product_id": "57471841-aa79-445d-b4f7-1cbd073a3188",
"data_product_name": "Checkout Flow",
"data_product_domain": "Marketing",
"version": 6
}
Properties and schema
PropertyDescription
id
string
Required. Identifier for the event specification that the event adheres to
name
string
Optional. Name for the event specification that the event adheres to
data_product_id
string
Optional. Identifier for the data product that the event specification belongs to
data_product_name
string
Optional. Name for the data product that the event specification belongs to
data_product_domain
string
Optional. Domain for the data product that the event specification belongs to
version
integer
Optional. Version of the event specification that the event adheres to

Property rules and instructions

Snowtype will take into account property rules that you define within your event specifications.

For example, if you add an instruction that a property must have one of a specific set of values, Snowtype will generate a type for that property that only allows those values.

If you include an instruction that's a detailed explanation of how to implement the data, this will be included as a comment in the generated code. It'll replace the description from the underlying data structure.

Snowtype supports entity cardinality rules for the Browser tracker only.

Event specification version

Changes to instructions increase the event specification version number. Your lockfile pins specific event specification versions.

If you don't see the expected updates in your generated code after making changes, try running snowtype update.

This example uses the User Log In event specification from the previous section. Within the Login event data structure, property rules have been set for two of the properties:

  • error_code: a detailed instruction explaining what values to supply
  • method: an enum rule limiting the allowed values to email, google, apple, and saml

In the generated output, the instruction on error_code appears as an inline comment, and method becomes a union type instead of string:

tsxGenerated output (excerpt)
// Before instructions

export type Login = {
/**
* An optional error code if the login attempt failed (e.g., 'invalid_password',
* 'user_not_found').
*/
error_code?: null | string;
/**
* Whether the login attempt was successful.
*/
is_success: boolean;
/**
* The method used to authenticate, such as 'email', 'google', 'apple', or 'saml'.
*/
method: string;
}

// After instructions

export type Login = {
/**
* Provide the raw error code from the authentication service, for example:
* 'AUTH_001' for invalid credentials, 'AUTH_002' for an expired session,
* or 'AUTH_003' for a locked account. Leave null if the login succeeded.
*/
error_code?: null | string;
/**
* Whether the login attempt was successful.
*/
is_success: boolean;
/**
* The method used to authenticate, such as 'email', 'google', 'apple', or 'saml'.
*/
method: LoginMethod;
}

/**
* The method used to authenticate, such as 'email', 'google', 'apple', or 'saml'.
*/
export type LoginMethod = "email" | "google" | "apple" | "saml";

Markdown instructions

When generating code for event specifications, you can also produce a Markdown file containing the implementation instructions defined for each specification. This can be useful for sharing implementation requirements with developers who may not have access to Console.

Use the --instructions flag:

bash
npx snowtype generate --instructions

The generated Markdown includes:

  • Trigger descriptions
  • Implementation rules
  • Images uploaded on your event specification triggers
  • App identifiers and URLs where the event should fire
  • Links to the generated code for each event specification

If you generate code for multiple event specifications, the instructions for each will be included in the same file, separated by headings.

This example shows the generated instruction file for a User Log In event specification:

markdown
# Implementation instructions

_A guide on how to implement tracking for the generated Event Specifications._

**Table of contents:**
- [User Log In](#user-log-in)


## [User Log In](https://console.snowplowanalytics.com/177234df-d425-412e-ad8d-8b97515b2807/data-products/57471841-aa79-445d-b4f7-1cbd073a3188/event-specifications/a965caf1-88a6-4a89-9aea-cc92516a9d56)

| | |

| ----------- | ----------- |
| **Id** | a965caf1-88a6-4a89-9aea-cc92516a9d56 |
| **Version** | 8 |
| **Data Product Id** | 57471841-aa79-445d-b4f7-1cbd073a3188 |
| **Source Application/s** | None selected |
| **Event Data Structure** | login/1-0-0 |
| **Entity Data Structures** | user/1-0-1, user_authentication/1-0-0 |
| **Code** | [Link](./snowplow.ts#L185) |
| **Data Product Domain** | Marketing |



#### Entity Cardinality Rules
| Name | Required | Number of entities |

| ----------- | ----------- | ----------- |
user | ❌ | Between `0` and `1`
user_authentication | ✅ | Exactly `1`



### Trigger

#### Screenshot
_N/A_

#### In which application(s) does this trigger apply?

_N/A_

#### The URL of the page on which this event specification triggers:

_N/A_

#### Notes

Track this when the user clicks the Log in button on the log in form/selection modal

Prevent generation from development schemas

When you are developing new data structures, they may only be deployed to your development environment. Generating and using tracking code from development-only schemas and shipping it to production can cause failed events, because the production pipeline doesn't have those schemas.

By default, Snowtype prints a warning when it detects development-only schemas:

bash
✔: Valid configuration found
⠦ Generating...
⚠ Warning: Generating code using schemas in DEV environment, tracking against those will result in failed events. Schemas in DEV:
iglu:com.snplow.msc.aws/user_authentication/jsonschema/1-0-0

✔: Code generated, writing...

To turn this into a hard error that stops generation, use the --disallowDevSchemas flag:

bash
npx snowtype generate --disallowDevSchemas
bash
✔: Valid configuration found
⠼ Generating...
⚠ Warning: Generating code using schemas in DEV environment, tracking against those will result in failed events. Schemas in DEV:
iglu:com.snplow.msc.aws/user_authentication/jsonschema/1-0-0

✗ Error: Code generation using schemas in DEV environment not allowed. Publish the schemas and retry.

This is especially useful in CI/CD pipelines where you want to catch the problem before code reaches production.

Use the generated code

How to implement the generated code depends on the tracker and language you're using.

This example demonstrates how to use Snowtype's generated code for the Browser tracker, based on the generated code shown above.

Check out the full data structures and event specifications example pages for different languages and trackers.

Using the generated data structure and Iglu Central schema code from the previous section:

typescript
import {
trackWebPage,
createProduct,
WebPage,
Product,
createWebPage,
} from "./{outpath}/snowplow";

/* Track a self-describing event */
trackWebPage({ id: "212a9b63-1af7-4e96-9f35-e2fca110ff43" });

/* Track an event with an entity attached */
const productEntity = createProduct({
id: "Product id",
name: "Snowplow product",
currency: "EUR",
price: 10,
category: "Snowplow/Shoes",
});
trackWebPage({
id: "212a9b63-1af7-4e96-9f35-e2fca110ff43",
context: [productEntity],
});

/* Enforce specific entity types using type arguments */
const webPageEntity = createWebPage({
id: "212a9b63-1af7-4e96-9f35-e2fca110ff43",
});
trackWebPage<Product | WebPage>({
id: "212a9b63-1af7-4e96-9f35-e2fca110ff43",
context: [productEntity, webPageEntity],
});

Using the generated event specification code from the previous section:

typescript
import {
trackUserLogInSpec,
createUser,
createUserAuthentication,
} from "./src/tracking/snowplow";

const userEntity = createUser({
userId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
firstName: "Ada",
lastName: "Lovelace",
organizationId: "57471841-aa79-445d-b4f7-1cbd073a3188",
email: "ada@example.com",
accessLevel: "Admin",
});

const userAuthEntity = createUserAuthentication({ auth_type: "google" });

trackUserLogInSpec({
method: "google",
is_success: true,
context: [userEntity, userAuthEntity],
});

Deprecation and hidden warnings

When you generate code from event specifications, Snowtype checks whether the data structures referenced by each specification are up to date. If a newer version of a data structure exists, or if the data structure has been hidden in Console, Snowtype adds a warning comment to the generated tracking function.

There are two types of warnings:

  • Outdated data structure: the event specification references a data structure version that isn't the latest. Snowtype marks the generated function with @deprecated Outdated data structure detected. in JavaScript/TypeScript, or an equivalent comment in other languages.
  • Hidden data structure: the event specification references a data structure that has been hidden in Console. Snowtype marks the generated function with Warning: Hidden data structure detected.

If both conditions apply, both warnings appear together:

typescript
/**
* @deprecated Outdated data structure detected.
* Warning: Hidden data structure detected.
* Tracks a MakesPurchase event specification.
* ID: 132a582b-88f3-4bcc-b1d5-c89e5813bbc9
*/
export function trackMakesPurchaseSpec(
...
)

These warnings surface in your IDE so you can see which event specifications need attention.

Show warnings only for production-deployed updates

By default, Snowtype flags outdated data structures in event specifications, regardless of where the newer version is deployed. If you only want to see deprecation warnings when a newer version has been deployed to your production environment, use the --deprecateOnlyOnProdAvailableUpdates flag:

bash
npx snowtype generate --deprecateOnlyOnProdAvailableUpdates

This suppresses outdated warnings when the newer schema version only exists in development, which can reduce noise during active development. You can also set this in your configuration file.

Name collisions and reusing objects

Snowtype has built-in logic to handle multiple uses of the same data structures, and limited support for handling name collisions.

Multiple versions of the same schema

If you generate code for multiple versions of the same data structure or Iglu Central schema, Snowtype will automatically disambiguate them by appending numbers to the types and function names.

For example, if you provide iglu:com.example/message_delayed/jsonschema/2-0-0 and iglu:com.example/message_delayed/jsonschema/3-0-0 in your configuration, the generated code will include e.g. type MessageDelayed (no number for the first instance) and type MessageDelayed1 (number appended for subsequent instances).

The numbering is based on the order of the sources in your configuration file. Snowtype processes local repository data structures first, then Iglu Central schemas, then Console data structures.

Same data structure in multiple event specifications

If you use the same data structure in multiple event specifications, Snowtype will generate only one set of functions for that data structure. You can use them wherever they're needed.

If you use the same data structure with different instructions or property rules in different event specifications, Snowtype will automatically disambiguate them based on the name of the event specification.

For example, you may have two event specifications, Add To Cart and User Log In, using the same user entity data structure with different instructions. Snowtype will generate code that includes e.g. type User (no suffix for the first instance) and type UserUserLogIn (event specification name appended for subsequent instances).

Snowtype will always add the name suffix for a data structure that has instructions, even if you've removed the instructions from it.

The autogenerated inline documentation comments and types will tell you which functions to use.

Event specifications with the same name

If you have multiple event specifications with the same name, you might experience name collisions, depending on which tracker you're using.

Use unique names

We recommend giving each event specification a unique name.

In Kotlin, Swift, and Dart, Snowtype uses the tracking plan name for extensions, which prevents name collisions.

For example, you may have two event specifications with the same name, User Log In, in two different tracking plans, Checkout Flow and User Management. In the Checkout Flow tracking plan, the User Log In event specification has the event data structure login. In the User Management tracking plan, the User Log In event specification has the event data structure authentication_attempt.

When you generate code for these specifications in Kotlin or Swift, Snowtype produces two separate functions to track each specification, with different extension functions based on the tracking plan name:

kotlin
fun Login.toUserLogInSpec() // for Checkout Flow
fun AuthenticationAttempt.toUserLogInSpec() // for User Management

In other languages, the generated function names are based only on the event specification name, which can lead to collisions if you have multiple specifications with the same name.

typescript
// For Checkout Flow
export function trackUserLogInSpec(userLogIn: Login & ContextsOrTimestamp, trackers?: string[])

// For User Management — duplicate identifier causes SyntaxError
export function trackUserLogInSpec(userLogIn: AuthenticationAttempt & ContextsOrTimestamp, trackers?: string[])

Snowtype limitations

Snowtype does not work with tracking plan templates. Track these manually using the standard tracker API.

Excluded schemas

Snowtype doesn't generate code for certain out-of-the-box Snowplow event schemas. Use the standard tracker API to track the event data structure as a self-describing event, or use the out-of-the-box tracking functionality.

If your event specification uses any of these schemas for the event data structure, Snowtype will generate code for the event specification and entities only:

  • iglu:com.snowplowanalytics.snowplow/page_ping/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/page_view/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1
  • iglu:com.snowplowanalytics.snowplow/button_click/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/expose_element/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/create_element/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/custom_event/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/application_background/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.snowplow/application_foreground/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.mobile/screen_view/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.mobile/screen_end/jsonschema/1-0-0
  • iglu:com.snowplowanalytics.mobile/application_install/jsonschema/1-0-0

You'll see a warning logged when you generate code using these: Warning: Currently code will not be generated for Standard events. Skipping.