Audience-targeted copy variants
The same product serves very different people. A free-tier user visiting the billing page should see different copy than an enterprise customer. A user who has not completed onboarding should see an encouraging nudge; one who has should not. When these variants are managed in application code - with if (user.plan === 'pro') conditionals scattered across components - the rules become invisible to anyone who is not reading the code. Changes require a deployment. Reviewers cannot see the full set of variants in one place.
Messagevisor moves those rules into the translation layer, where they are visible, testable, and changeable independently of the application.
The model: overrides with segments#
Every Messagevisor message can have an overrides array. Each override defines which audience should receive an alternate translation, expressed as a segment reference or an inline condition. The SDK evaluates the overrides at runtime against the active context and returns the first matching translation.
This model keeps the conditional logic in the definition, not in the application. The application calls translate("billing.upgrade") and receives the right string for that user. It never contains the logic for which string to return.
Defining reusable audience segments#
Start by defining the audience rules as named segments. This makes them reviewable, testable, and reusable across multiple messages.
description: Users on the Pro planconditions: attribute: plan operator: equals value: prodescription: Users on the Enterprise planconditions: attribute: plan operator: equals value: enterprisedescription: Users who have not completed onboardingconditions: attribute: onboardingComplete operator: equals value: falsedescription: Users who signed up in the last 30 daysconditions: attribute: daysSinceSignup operator: lessThanOrEquals value: 30Applying overrides to a message#
With segments defined, apply them as overrides in a message. Overrides are evaluated top-to-bottom; the first match wins.
description: Call to action on the billing pagetranslations: en: Upgrade your plan nl: Upgrade je abonnementoverrides: - key: enterprise segments: plan-enterprise translations: en: Talk to your account manager nl: Neem contact op met uw accountmanager - key: pro segments: plan-pro translations: en: Explore add-ons for your Pro plan nl: Ontdek uitbreidingen voor je Pro-abonnementEnterprise users see the account manager prompt. Pro users see the add-ons prompt. Everyone else sees the default upgrade CTA.
Composing segments for complex audiences#
Use logical composition when a variant should apply to multiple audiences simultaneously:
description: Dashboard welcome headingtranslations: en: Welcome back nl: Welkom terugoverrides: - key: new-pro-user segments: and: - plan-pro - new-user translations: en: Welcome to Pro - let's get you set up nl: Welkom bij Pro - we helpen je op weg - key: incomplete-onboarding segments: onboarding-incomplete translations: en: Pick up where you left off nl: Ga verder waar je gebleven was - key: pro segments: plan-pro translations: en: Welcome back to your Pro workspace nl: Welkom terug in je Pro-werkruimteThe new-pro-user override fires for users who match both plan-pro and new-user. Because it appears first, it takes precedence over the more general pro override for that audience.
Using inline conditions for one-off logic#
When the condition is too specific to warrant its own segment file, write it inline:
description: Trial expiry bannertranslations: en: Your trial ends soon nl: Je proefperiode loopt bijna afoverrides: - key: trial-urgent conditions: attribute: trialDaysRemaining operator: lessThanOrEquals value: 3 translations: en: "Your trial ends in {trialDaysRemaining, number} days - upgrade now to keep your data" nl: "Je proefperiode eindigt over {trialDaysRemaining, number} dagen - upgrade nu om je data te bewaren" - key: trial-ending conditions: attribute: trialDaysRemaining operator: lessThanOrEquals value: 7 translations: en: "Your trial ends in {trialDaysRemaining, number} days" nl: "Je proefperiode eindigt over {trialDaysRemaining, number} dagen"Passing context from the application#
The application supplies the runtime context. The SDK matches it against segment conditions to determine which override applies:
import { createMessagevisor } from "@messagevisor/sdk";import datafile from "./datafiles/messagevisor-web-en-US.json";const m = createMessagevisor({ datafile, locale: "en-US", context: { platform: "web", plan: currentUser.plan, onboardingComplete: currentUser.onboardingComplete, daysSinceSignup: currentUser.daysSinceSignup, trialDaysRemaining: currentUser.trialDaysRemaining, },});// Returns the right variant for this user automaticallyconst upgradeLabel = m.translate("billing.upgrade");The context can be updated as user state changes without reinstantiating the SDK:
m.setContext({ plan: updatedUser.plan, onboardingComplete: updatedUser.onboardingComplete,});React usage#
import { useMessagevisor, useTranslation } from "@messagevisor/react";function BillingPage() { const upgradeLabel = useTranslation("billing.upgrade"); return <button>{upgradeLabel}</button>;}The hook re-evaluates when locale, context, or datafile changes, so locale switches or plan upgrades in a live session reflect immediately.
Testing audience variants#
Write explicit assertions for each audience to catch regressions when segments or overrides change:
message: billing.upgradeassertions: - description: Default for free users locale: en target: web context: plan: free expectedTranslation: Upgrade your plan - description: Pro variant locale: en target: web context: plan: pro expectedTranslation: Explore add-ons for your Pro plan - description: Enterprise variant locale: en target: web context: plan: enterprise expectedTranslation: Talk to your account manager - description: New Pro user sees setup prompt locale: en target: web context: plan: pro daysSinceSignup: 5 expectedTranslation: Welcome to Pro - let's get you set upThese tests run in CI and catch any change that silently breaks an audience variant before it reaches production.
Reviewing all variants in the catalog#
The catalog renders each message with all its overrides and the associated segment conditions expanded. Product managers and content editors can review what each audience sees without reading YAML or running CLI commands. Deep-linkable rows make it easy to point a stakeholder at a specific variant for sign-off.
$ npx messagevisor catalog
