Event SpecsSaaS / B2B

SaaS / B2B Event Spec

This page defines all standard events for SaaS and B2B software products on Datafly Signal. The taxonomy covers the full customer lifecycle — discovery and lead capture, sign-up, trial, onboarding, subscription, in-product usage, retention, and team collaboration. Implement these events to enable accurate server-side delivery to advertising and analytics platforms.

💡

Event names reuse GA4’s recommended names wherever there is an overlap (view_item, add_to_cart, purchase, search, sign_up, login, generate_lead). If you’re migrating from Google Tag Manager, those event names work as-is. SaaS-specific events use snake_case and map to vendor-native conversions in the Vendor Mapping table.

All events are sent via datafly.track(). Properties are passed as a flat object in the second argument. All event names and property names use snake_case.

⚠️

Never put raw PII (email, phone, name) in track() properties. Hash identifiers with SHA-256 (trim + lowercase first) before sending, and rely on Signal’s first-party identity layer for user stitching.


Discovery & Marketing

Events fired on your marketing site and pricing pages, before a user has an account.

view_item

Fired when a visitor views a marketing page for a specific product, plan, or feature. Also accepted as view_content.

datafly.track('view_item', {
  item_id: 'plan_pro',
  item_name: 'Pro',
  item_category: 'pricing',
  content_type: 'product'
})
PropertyTypeRequiredDescription
item_idstringOptionalIdentifier of the product, plan, or feature viewed
item_namestringOptionalHuman-readable name (e.g. Pro)
item_categorystringOptionalPage or content category (e.g. pricing, feature)
content_typestringOptionalType of content viewed (e.g. product, plan, feature)

plan_viewed

Fired when a user views a specific pricing plan or tier on the pricing page.

datafly.track('plan_viewed', {
  plan_id: 'plan_pro',
  plan_name: 'Pro',
  billing_cycle: 'monthly',
  price: 49.00,
  currency: 'GBP'
})
PropertyTypeRequiredDescription
plan_idstringOptionalInternal identifier for the plan
plan_namestringOptionalHuman-readable plan name (e.g. Pro)
billing_cyclestringOptionalCycle shown (monthly or annual)
pricenumberOptionalDisplayed price of the plan
currencystringOptionalISO 4217 currency code (e.g. GBP, USD)

Fired when a user submits a search query against your site, docs, or in-app search.

datafly.track('search', {
  search_term: 'webhook integration',
  context: 'docs'
})
PropertyTypeRequiredDescription
search_termstringRequiredThe search term entered by the user
contextstringOptionalWhere the search ran (e.g. marketing, docs, app)

view_promotion

Fired when a promotional banner, offer, or campaign creative is visible to the user.

datafly.track('view_promotion', {
  promotion_id: 'LAUNCH20',
  promotion_name: 'Launch 20% Off',
  creative_name: 'pricing-banner-v2',
  creative_slot: 'pricing-hero'
})
PropertyTypeRequiredDescription
promotion_idstringOptionalIdentifier for the promotion
promotion_namestringOptionalHuman-readable name of the promotion
creative_namestringOptionalName or URL of the creative asset shown
creative_slotstringOptionalSlot or placement where the promotion appeared

Lead Generation

Events that capture marketing-qualified intent: demo requests, content downloads, and form fills.

generate_lead

Fired when a user submits a lead-capture form (contact sales, newsletter, gated content). This is the primary top-of-funnel conversion for B2B campaigns.

datafly.track('generate_lead', {
  lead_source: 'pricing_page',
  form_id: 'contact_sales',
  campaign: 'q3_enterprise',
  value: 0,
  currency: 'GBP'
})
PropertyTypeRequiredDescription
lead_sourcestringOptionalWhere the lead originated (e.g. pricing_page, blog, webinar)
form_idstringOptionalIdentifier of the form submitted
campaignstringOptionalMarketing campaign associated with the lead
valuenumberOptionalEstimated lead value for value-based bidding
currencystringOptionalISO 4217 currency code
⚠️

Do not include the submitted email, phone, or name in generate_lead properties. Signal hashes and forwards contact identifiers separately via the identity layer.


demo_requested

Fired when a user requests a product demo or books a sales call.

datafly.track('demo_requested', {
  lead_source: 'homepage',
  company_size: '50-200',
  plan_interest: 'enterprise',
  campaign: 'q3_enterprise'
})
PropertyTypeRequiredDescription
lead_sourcestringOptionalWhere the demo request originated
company_sizestringOptionalSelf-reported company size band (e.g. 50-200)
plan_intereststringOptionalPlan or tier the prospect is interested in
campaignstringOptionalMarketing campaign associated with the request

content_downloaded

Fired when a user downloads gated content such as a whitepaper, ebook, or template.

datafly.track('content_downloaded', {
  content_id: 'wp_saas_attribution',
  content_name: 'The SaaS Attribution Playbook',
  content_type: 'whitepaper',
  lead_source: 'blog'
})
PropertyTypeRequiredDescription
content_idstringOptionalStable identifier for the content asset
content_namestringOptionalHuman-readable title of the content
content_typestringOptionalType of asset (e.g. whitepaper, ebook, template)
lead_sourcestringOptionalWhere the download was triggered

Authentication

Events relating to user sign-up, sign-in, and account access.

sign_up

A new user has created an account.

datafly.track('sign_up', {
  method: 'google',
  plan: 'pro',
  referral_code: 'FRIEND2026'
})
PropertyTypeRequiredDescription
methodstringOptionalRegistration method: email, google, sso
planstringOptionalPlan selected at sign-up, if any (e.g. starter, pro)
invited_bystringOptionalUser ID of the person who sent the invitation
referral_codestringOptionalReferral code applied during sign-up

login

A user has successfully authenticated.

datafly.track('login', {
  method: 'sso'
})
PropertyTypeRequiredDescription
methodstringOptionalAuthentication method (e.g. email, sso, magic_link)

logout

A user has ended their session.

datafly.track('logout')

No additional properties.


password_reset_requested

A user has requested a password reset email.

datafly.track('password_reset_requested')

No additional properties.


Onboarding

Events tracking activation — the steps between sign-up and first value.

onboarding_started

A user has begun the onboarding or setup flow after creating an account.

datafly.track('onboarding_started', {
  flow_id: 'default_onboarding',
  plan: 'pro',
  total_steps: 5
})
PropertyTypeRequiredDescription
flow_idstringOptionalIdentifier of the onboarding flow entered
planstringOptionalPlan the user is onboarding onto
total_stepsnumberOptionalNumber of steps in the onboarding flow

onboarding_step_completed

A user has completed a single step within the onboarding flow.

datafly.track('onboarding_step_completed', {
  flow_id: 'default_onboarding',
  step_id: 'connect_data_source',
  step_index: 2,
  total_steps: 5
})
PropertyTypeRequiredDescription
flow_idstringOptionalIdentifier of the onboarding flow
step_idstringOptionalIdentifier of the completed step
step_indexnumberOptionalPosition of the step in the flow (0-indexed)
total_stepsnumberOptionalNumber of steps in the onboarding flow

onboarding_completed

A user has completed the full onboarding flow and reached activation.

datafly.track('onboarding_completed', {
  flow_id: 'default_onboarding',
  plan: 'pro',
  steps_completed: 5,
  time_to_complete_seconds: 420
})
PropertyTypeRequiredDescription
flow_idstringOptionalIdentifier of the onboarding flow completed
planstringOptionalPlan the user onboarded onto
steps_completednumberOptionalNumber of steps the user completed
time_to_complete_secondsnumberOptionalTotal time from start to completion in seconds

Trial & Subscription

Events relating to trial activation, conversion, and subscription lifecycle.

trial_started

A user has entered a free trial period.

datafly.track('trial_started', {
  plan_id: 'plan_pro',
  plan_name: 'Pro',
  trial_length_days: 14
})
PropertyTypeRequiredDescription
plan_idstringOptionalInternal identifier for the plan
plan_namestringOptionalHuman-readable plan name (e.g. Pro Trial)
trial_length_daysnumberOptionalNumber of days in the trial

trial_converted

A trial user has upgraded to a paid subscription.

datafly.track('trial_converted', {
  plan_id: 'plan_pro_monthly',
  plan_name: 'Pro Monthly',
  revenue: 49.00,
  currency: 'GBP',
  payment_method: 'card'
})
PropertyTypeRequiredDescription
plan_idstringOptionalPlan converted onto
plan_namestringOptionalHuman-readable plan name
revenuenumberOptionalFirst payment amount
currencystringOptionalISO 4217 currency code (e.g. GBP, USD)
payment_methodstringOptionalPayment method used (e.g. card, invoice)

trial_expired

A trial period ended without conversion.

datafly.track('trial_expired', {
  plan_id: 'plan_pro',
  days_used: 9,
  features_used: ['reporting', 'integrations']
})
PropertyTypeRequiredDescription
plan_idstringOptionalPlan that expired
days_usednumberOptionalNumber of trial days the user was active
features_usedstring[]OptionalList of feature IDs used during the trial

subscription_started

A new paid subscription has been activated. This is the primary revenue conversion event for SaaS.

datafly.track('subscription_started', {
  plan_id: 'plan_pro_annual',
  plan_name: 'Pro Annual',
  revenue: 468.00,
  currency: 'GBP',
  billing_cycle: 'annual',
  coupon: 'LAUNCH20'
})
PropertyTypeRequiredDescription
plan_idstringYesPlan identifier
plan_namestringOptionalHuman-readable plan name
revenuenumberOptionalAmount charged
currencystringOptionalISO 4217 currency code
billing_cyclestringOptionalmonthly or annual
couponstringOptionalCoupon or promo code applied
⚠️

Send a stable subscription or transaction identifier where possible so Meta CAPI and GA4 can deduplicate against browser-side conversions.


subscription_upgraded

A subscriber has moved to a higher-tier plan.

datafly.track('subscription_upgraded', {
  previous_plan_id: 'plan_starter_monthly',
  new_plan_id: 'plan_pro_monthly',
  revenue_delta: 30.00,
  currency: 'GBP'
})
PropertyTypeRequiredDescription
previous_plan_idstringOptionalPlan being upgraded from
new_plan_idstringYesPlan being upgraded to
revenue_deltanumberOptionalAdditional revenue from the upgrade (prorated or full cycle)
currencystringOptionalISO 4217 currency code

subscription_downgraded

A subscriber has moved to a lower-tier plan.

datafly.track('subscription_downgraded', {
  previous_plan_id: 'plan_pro_monthly',
  new_plan_id: 'plan_starter_monthly',
  reason: 'too_expensive'
})
PropertyTypeRequiredDescription
previous_plan_idstringOptionalPlan being downgraded from
new_plan_idstringYesPlan being downgraded to
reasonstringOptionalReason code or label provided by the user

subscription_cancelled

A subscription has been cancelled.

datafly.track('subscription_cancelled', {
  plan_id: 'plan_pro_monthly',
  reason: 'switching_product',
  feedback: 'Moving to a tool with better API support'
})
PropertyTypeRequiredDescription
plan_idstringOptionalPlan being cancelled
reasonstringOptionalCancellation reason code (e.g. missing_feature, switching_product)
feedbackstringOptionalFree-text feedback from the user
⚠️

Do not send raw email addresses in feedback. If your cancellation flow captures open text, sanitise or omit it before sending.


subscription_renewed

A subscription billing cycle has renewed successfully.

datafly.track('subscription_renewed', {
  plan_id: 'plan_pro_annual',
  revenue: 468.00,
  currency: 'GBP'
})
PropertyTypeRequiredDescription
plan_idstringOptionalPlan that renewed
revenuenumberOptionalAmount charged on renewal
currencystringOptionalISO 4217 currency code

Product Usage

Events tracking in-product engagement and feature adoption.

feature_used

A user has interacted with a specific product feature.

datafly.track('feature_used', {
  feature_id: 'bulk_export',
  feature_name: 'Bulk Export',
  context: 'reports'
})
PropertyTypeRequiredDescription
feature_idstringYesStable identifier for the feature (e.g. bulk_export)
feature_namestringOptionalHuman-readable feature name
contextstringOptionalWhere in the UI the feature was used (e.g. dashboard, settings)

report_viewed

A user has opened or refreshed a report.

datafly.track('report_viewed', {
  report_id: 'rpt_monthly_revenue',
  report_name: 'Monthly Revenue',
  filters: { date_range: 'last_30_days', segment: 'pro_users' }
})
PropertyTypeRequiredDescription
report_idstringOptionalStable identifier for the report
report_namestringOptionalDisplay name (e.g. Monthly Revenue)
filtersobjectOptionalActive filter state at time of view

export_completed

A data export has finished successfully.

datafly.track('export_completed', {
  export_type: 'csv',
  record_count: 1450
})
PropertyTypeRequiredDescription
export_typestringOptionalFormat of the export: csv, pdf, xlsx
record_countnumberOptionalNumber of records included in the export

integration_connected

A user has successfully connected a third-party integration.

datafly.track('integration_connected', {
  integration_id: 'int_salesforce',
  integration_name: 'Salesforce',
  provider: 'salesforce'
})
PropertyTypeRequiredDescription
integration_idstringYesStable identifier for the integration
integration_namestringOptionalDisplay name (e.g. Salesforce)
providerstringOptionalProvider/vendor name

api_key_created

A user has generated a new API key.

datafly.track('api_key_created', {
  scope: 'read_only'
})
PropertyTypeRequiredDescription
scopestringOptionalPermission scope of the key (e.g. read_only, full_access)

Retention & Support

Events relating to ongoing engagement, support interactions, and account health.

support_ticket_created

A user has opened a support ticket or contacted support.

datafly.track('support_ticket_created', {
  ticket_id: 'tkt_84021',
  category: 'billing',
  priority: 'high',
  channel: 'in_app'
})
PropertyTypeRequiredDescription
ticket_idstringOptionalIdentifier of the created ticket
categorystringOptionalTicket category (e.g. billing, technical, account)
prioritystringOptionalPriority level (e.g. low, normal, high)
channelstringOptionalChannel the ticket came in on (e.g. in_app, email, chat)

feedback_submitted

A user has submitted in-product feedback, an NPS score, or a survey response.

datafly.track('feedback_submitted', {
  survey_id: 'nps_q3',
  feedback_type: 'nps',
  score: 9
})
PropertyTypeRequiredDescription
survey_idstringOptionalIdentifier of the survey or prompt
feedback_typestringOptionalType of feedback (e.g. nps, csat, feature_request)
scorenumberOptionalNumeric score where applicable (e.g. NPS 0–10)
⚠️

Do not include free-text feedback containing personal data in event properties. Send only the score and survey identifiers.


referral_sent

An existing user has referred another person to the product.

datafly.track('referral_sent', {
  referral_code: 'FRIEND2026',
  channel: 'email',
  reward_type: 'account_credit'
})
PropertyTypeRequiredDescription
referral_codestringOptionalReferral code shared by the user
channelstringOptionalChannel used to share the referral (e.g. email, link, social)
reward_typestringOptionalReward associated with the referral (e.g. account_credit, discount)

Collaboration & Team

Events relating to team invitations, seat management, and multi-user activity.

invitation_sent

A team member has been invited to the workspace.

datafly.track('invitation_sent', {
  invitee_email_hash: 'b3a8e0e1...', // SHA-256 of invitee email
  role: 'member',
  seats_total: 8
})
PropertyTypeRequiredDescription
invitee_email_hashstringOptionalSHA-256 hash of the invitee’s email address
rolestringOptionalRole assigned to the invitee (e.g. admin, member, viewer)
seats_totalnumberOptionalTotal seat count on the account after sending the invitation
⚠️

Never send raw email addresses as event properties. Hash using SHA-256 (trim + lowercase first) before tracking.


invitation_accepted

An invited user has accepted their invitation and joined the workspace.

datafly.track('invitation_accepted', {
  inviter_id: 'user_123',
  role: 'member'
})
PropertyTypeRequiredDescription
inviter_idstringOptionalUser ID of the person who sent the invitation
rolestringOptionalRole the new user was assigned

seat_added

A new seat has been added to the account.

datafly.track('seat_added', {
  new_seat_count: 10
})
PropertyTypeRequiredDescription
new_seat_countnumberOptionalTotal seat count after the addition

seat_removed

A seat has been removed from the account.

datafly.track('seat_removed', {
  new_seat_count: 9,
  reason: 'user_offboarded'
})
PropertyTypeRequiredDescription
new_seat_countnumberOptionalTotal seat count after the removal
reasonstringOptionalReason for removal (e.g. user_offboarded, downgrade)

Vendor Mapping

The table below shows how Datafly Signal maps SaaS events to the native event names expected by each vendor’s server-side API. Signal uses the GA4-style event names as its canonical format, and blueprints handle the transformation to vendor-specific payloads. *(custom)* indicates the vendor has no native equivalent, so Signal delivers the event under its own name as a custom event.

Signal EventGA4Meta CAPITikTok Events API
view_itemview_itemViewContentViewContent
plan_viewedview_itemViewContentViewContent
searchsearchSearchSearch
view_promotionview_promotion(custom)(custom)
generate_leadgenerate_leadLeadSubmitForm
demo_requestedgenerate_leadLeadSubmitForm
content_downloadedgenerate_leadLeadDownload
sign_upsign_upCompleteRegistrationCompleteRegistration
loginlogin(custom)(custom)
logout(custom)(custom)(custom)
password_reset_requested(custom)(custom)(custom)
onboarding_startedtutorial_begin(custom)(custom)
onboarding_step_completed(custom)(custom)(custom)
onboarding_completedtutorial_completeCompleteRegistrationCompleteRegistration
trial_startedbegin_checkoutStartTrialStartTrial
trial_convertedpurchaseSubscribeSubscribe
trial_expired(custom)(custom)(custom)
subscription_startedpurchaseSubscribeSubscribe
subscription_upgradedpurchaseSubscribeSubscribe
subscription_downgraded(custom)(custom)(custom)
subscription_cancelled(custom)(custom)(custom)
subscription_renewedpurchaseSubscribeSubscribe
feature_usedfeature_used(custom)(custom)
report_viewedview_itemViewContentViewContent
export_completed(custom)(custom)(custom)
integration_connected(custom)(custom)(custom)
api_key_created(custom)(custom)(custom)
support_ticket_createdcontactContactContact
feedback_submitted(custom)(custom)(custom)
referral_sentshare(custom)(custom)
invitation_sentshare(custom)(custom)
invitation_acceptedjoin_groupCompleteRegistrationCompleteRegistration
seat_added(custom)(custom)(custom)
seat_removed(custom)(custom)(custom)