Capturing events
Contents
Once your PostHog instance is up and running, the next step is to start sending events.
By default, PostHog automatically captures pageviews and pageleaves as well as clicks, change of inputs, and form submissions associated with a, button, form, input, select, textarea, and label tags. See our autocapture docs for more details on this.
If you prefer to disable or filter these, set the appropriate values in your configuration options.
Custom event capture
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Tip: You can define event schemas with typed properties and generate type-safe code using schema management.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Capturing pageviews
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send $pageview events from your backend like so:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Tip: You can define event schemas with typed properties and generate type-safe code using schema management.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Sending page views
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send pageviews from your backend like so:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Sending page views
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send pageviews from your backend like so:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Sending pageviews
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send pageviews from your backend like so:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Tip: You can define event schemas with typed properties and generate type-safe code using schema management.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Capturing pageviews
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send pageviews from your backend like so:
By default, PostHog automatically captures pageviews and pageleaves as well as clicks, change of inputs, and form submissions associated with a, button, form, input, select, textarea, and label tags. See our autocapture docs for more details on this.
If you prefer to disable or filter these, set the appropriate values in your configuration options.
Capturing custom events
After setting up the PostHog provider, you can use the usePostHog hook to access all the methods of the posthog-js library including capture which lets you capture custom events with optional properties.
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Capturing screen views
With @react-navigation/native and autocapture:
When using @react-navigation/native v6 or lower, screen tracking is automatically captured if the autocapture property is used in the PostHogProvider:
It is important that the PostHogProvider is configured as a child of the NavigationContainer:
When using @react-navigation/native v7 or higher, screen tracking has to be manually captured:
Check out and set it up the official way for Screen tracking for analytics.
Then call the screen method within the trackScreenView method.
With react-native-navigation and autocapture:
First, simplify the wrapping of your screens with a shared PostHogProvider:
Then, every screen needs to be wrapped with this provider if you want to capture touches or use the usePostHog() hook
With expo-router:
Check out and set it up the official way for Screen tracking for analytics.
Then call the screen method within the useEffect callback.
Manually capturing screen capture events
If you prefer not to use autocapture, you can manually capture screen views by calling posthog.screen(). This function requires a name. You may also pass in an optional properties object.
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Autocapture
PostHog autocapture automatically tracks the following events for you:
- Application Opened - when the app is opened from a closed state or when the app comes to the foreground. (e.g. from the app switcher)
- Deep Link Opened - when the app is opened from a deep link.
- Application Backgrounded - when the app is sent to the background by the user.
- Application Installed - when the app is installed.
- Application Updated - when the app is updated.
- $screen - when the user navigates. (if using
android.app.Activity) - $exception - when the app throws exceptions.
Capturing screen views
With captureScreenViews = true, PostHog will try to record all screen changes automatically.
The screenTitle will be the <activity>'s android:label, if not set it'll fallback to the <application>'s android:label or the <activity>'s android:name.
If you want to manually send a new screen capture event, use the screen function.
This function requires a screenTitle. You may also pass in an optional properties object.
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Autocapture
PostHog autocapture automatically tracks the following events for you:
- Application Opened - when the app is opened from a closed state or when the app comes to the foreground (e.g. from the app switcher)
- Application Backgrounded - when the app is sent to the background by the user
- Application Installed - when the app is installed
- Application Updated - when the app is updated
- $screen - when the user navigates (if using
UIViewController) - $autocapture - when the user interacts with elements in a screen (if using
UIKit)
🚧 Note:
$autocaptureis currently supported only in UIKit.
Capturing screen views
With configuration.captureScreenViews set as true, PostHog will try to record all screen changes automatically.
If you want to manually send a new screen capture event, use the screen function.
Important: While
captureScreenViewsworks with bothUIKitandSwiftUI, the screen names captured inSwiftUImay not be very meaningful as they are based on internal SwiftUI view identifiers. ForSwiftUIapplications, we recommend turning this option off and instead using the.postHogScreenView()view modifier (see next section) to capture screen views with meaningful names.
Note: You can use the
BeforeSendBlockto filter or drop any undesired screen events, giving you control over which screen views are sent to PostHog. See Amending, dropping or sampling events for implementation examples.
Capturing screen views in SwiftUI
To track a screen view in SwiftUI, apply the postHogScreenView modifier to your full-screen views.
PostHog will send a $screen event when the onAppear action is executed and will infer a screen name based on the view’s type. You can provide a custom name and event properties if needed.
In SwiftUI, views can range from entire screens to small UI components. Unlike UIKit, SwiftUI doesn’t clearly distinguish between these levels, which makes automatic tracking of full-screen views harder.
Adding a custom label on autocaptured elements
PostHog automatically captures interactions with various UI elements in your app, but these interactions are often identified by element type names (e.g., UIButton, UITextField, UILabel).
While this provides basic tracking, it can be challenging to pinpoint specific interactions with particular elements in your analytics. To make your data more meaningful and actionable, you can assign custom labels to any autocaptured element. These labels act as descriptive identifiers, making it easier to identify, filter, and analyze events in your reports.
Adding a custom label in UIKit
To assign a custom label to a UIView, use the postHogLabel property:
In this example, interactions with the UITextField will be captured with an additional identifier "usernameTextField".
Adding a custom label in SwiftUI
In SwiftUI, use the .postHogLabel(_:) modifier instead:
In this example, interactions with the underlying UITextField will be captured with an additional identifier "usernameTextField".
Example of generated analytics data
The generated analytics element in the examples above will have the following form:
Filtering for labeled autocaptured elements in reports
To locate and filter interactions with specific elements in PostHog reports, you can use Autocapture element filters, such as:
- Tag Name (
UITextFieldin this example) - Text (
text valuein this example) - CSS Selector (the generated
idattribute in this example)
In the examples above, we can filter for the specific text field using the CSS Selector #usernameTextField
Interaction autocapture
Interaction autocapture records when users interact with UI elements in your app. This includes:
- User interactions like
touch,swipe,pan,pinch,rotation,long_press,scroll - Control types
value_changed,submit,toggle,primary_action,menu_action,change
Interaction autocapture is not enabled by default. You can enable it by setting captureElementInteractions to true in the config.
Autocapture configuration
You can enable or disable autocapture through the PostHogConfig object. Find more details about autocapture configuration in the configuration page.
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Batching events
To capture multiple events at once, use batch():
To capture an event, use PostHog.capture/2:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Context
Carrying distinct_id around all the time might not be the most convenient approach, so PostHog lets you store it and other properties in a context.
The context is stored in the Logger metadata and PostHog automatically attaches these properties to any events you capture with PostHog.capture/2, as long as they happen in the same process.
You can also scope the context to a specific event name:
Batching events
Events are automatically batched and sent to PostHog via a background job.
Special events
PostHog.capture/2 is very powerful and enables you to send events that have special meaning.
In other libraries you'll usually find helpers for these special events, but they must be explicitly sent in Elixir.
For example:
Create alias
Group analytics
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Autocapture
PostHog autocapture automatically tracks the following events for you:
- Application Opened - when the app is opened from a closed state or when the app comes to the foreground (e.g. from the app switcher)
- Application Backgrounded - when the app is sent to the background by the user
- Application Installed - when the app is installed.
- Application Updated - when the app is updated.
- $screen - when the user navigates (if using navigatorObservers or go_router. You'd need to set up the
PosthogObservermanually.) - $exception - when the app throws exceptions.
Capturing screen views
Note: Your routes should be named. Otherwise, they won't be recorded.
Using navigatorObservers
Add the PosthogObserver to record screen views automatically:
Name your routes:
Using go_router
Add the PosthogObserver to record screen views automatically:
Name your routes:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Sending page views
If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send $pageview events from your backend like so:
You can send custom events using capture:
Tip: We recommend using a
[object] [verb]format for your event names, where[object]is the entity that the behavior relates to, and[verb]is the behavior itself. For example,project created,user signed up, orinvite sent.
Setting event properties
Optionally, you can include additional information with the event by including a properties object:
Batching events
Events can be sent together in a batch. There is no limit on the number of events you can send in a batch, but the entire request body must be less than 20MB by default.
Event ingestion
It's a priority for us that events are fully processed and saved as soon as possible. Typically, events will be usable in queries within a few minutes.
Advanced: Anonymous vs identified events
PostHog captures two types of events: anonymous and identified
Identified events enable you to attribute events to specific users, and attach person properties. They're best suited for logged-in users.
Scenarios where you want to capture identified events are:
- Tracking logged-in users in B2B and B2C SaaS apps
- Doing user segmented product analysis
- Growth and marketing teams wanting to analyze the complete conversion lifecycle
Anonymous events are events without individually identifiable data. They're best suited for web analytics or apps where users aren't logged in.
Scenarios where you want to capture anonymous events are:
- Tracking a marketing website
- Content-focused sites
- B2C apps where users don't sign up or log in
Under the hood, the key difference between identified and anonymous events is that for identified events we create a person profile for the user, whereas for anonymous events we do not.
Important: Due to the reduced cost of processing them, anonymous events can be up to 4x cheaper than identified ones, so we recommended you only capture identified events when needed.
How to capture anonymous events
The JavaScript Web SDK captures anonymous events by default. However, this may change depending on your person_profiles config when initializing PostHog:
person_profiles: 'identified_only'(recommended) (default) - Anonymous events are captured by default. PostHog only captures identified events for users where person profiles have already been created.person_profiles: 'always'- Capture identified events for all events.
For example:
PostHog's backend SDKs and API capture identified events by default. To capture anonymous events, set the $process_person_profile property to false:
The Android SDK captures anonymous events by default. However, this may change depending on your personProfiles config when initializing PostHog:
personProfiles = PersonProfiles.IDENTIFIED_ONLY(recommended) (default) - Anonymous events are captured by default. PostHog only captures identified events for users where person profiles have already been created.personProfiles = PersonProfiles.ALWAYS- Capture identified events for all events.personProfiles = PersonProfiles.NEVER- Capture anonymous events for all events.
For example:
The iOS SDK captures anonymous events by default. However, this may change depending on your personProfiles config when initializing PostHog:
personProfiles: .identifiedOnly(recommended) (default) - Anonymous events are captured by default. PostHog only captures identified events for users where person profiles have already been created.personProfiles: .always- Capture identified events for all events.personProfiles: .never- Capture anonymous events for all events.
For example:
The Flutter SDK captures anonymous events by default. However, this may change depending on your personProfiles config when initializing PostHog:
personProfiles: PostHogPersonProfiles.identifiedOnly(recommended) (default) - Anonymous events are captured by default. PostHog only captures identified events for users where person profiles have already been created.personProfiles: PostHogPersonProfiles.always- Capture identified events for all events.personProfiles: PostHogPersonProfiles.never- Capture anonymous events for all events.
For example:
How to capture identified events
If you've set the personProfiles config to IDENTIFIED_ONLY (the default option), anonymous events are captured by default. To capture identified events, call any of the following functions:
identify()alias()group()setPersonProperties()setPersonPropertiesForFlags()setGroupPropertiesForFlags()
When you call any of these functions, it creates a person profile for the user. Once this profile is created, all subsequent events for this user will be captured as identified events.
Alternatively, you can set personProfiles to ALWAYS to capture identified events by default.
PostHog's backend SDKs and API capture identified events by default.
If you've set the personProfiles config to IDENTIFIED_ONLY (the default option), anonymous events are captured by default. Then, to capture identified events, call any of the following functions:
When you call any of these functions, it creates a person profile for the user. Once this profile is created, all subsequent events for this user will be captured as identified events.
Alternatively, you can set personProfiles to ALWAYS to capture identified events by default.
If you've set the personProfiles config to IDENTIFIED_ONLY (the default option), anonymous events are captured by default. Then, to capture identified events, call any of the following functions:
When you call any of these functions, it creates a person profile for the user. Once this profile is created, all subsequent events for this user will be captured as identified events.
Alternatively, you can set personProfiles to ALWAYS to capture identified events by default.
If you've set the personProfiles config to IDENTIFIED_ONLY (the default option), anonymous events are captured by default. Then, to capture identified events, call any of the following functions:
When you call any of these functions, it creates a person profile for the user. Once this profile is created, all subsequent events for this user will be captured as identified events.
Alternatively, you can set personProfiles to ALWAYS to capture identified events by default.