> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Category onboarding for news and media

> Welcome Journey for news and media apps that nudges readers to complete their profile and pick category preferences using Yes/No branches, Wait Until steps, follow-up pushes, and tailored emails.

This playbook implements the [News and media strategies](./news-and-media-industry) hub's category opt-in onboarding flow as a multi-day Welcome Journey. The Journey progressively nudges readers to complete their profile, pick category preferences, and (optionally) confirm their email — without competing with editorial broadcasts that publish breaking news from the dashboard or API.

This Journey is **gap-driven**: each step checks whether the reader has already taken the action it would otherwise prompt, and stays silent if they have. A reader who arrives fully set up gets only the welcome and final emails. A reader who never returns gets the IAMs and follow-up pushes reinforcing what's still missing.

***

## At a glance

1. Send a [welcome email](#step-1-welcome-email) introducing the company, getting started in the app, and the community.
2. [Wait Until](#step-2-wait-until-profile-set) the reader has a profile — `account_type` exists, set only on identified users with an External ID and a completed profile. On expiration, show a Profile setup IAM.
3. [Wait Until](#step-3-wait-until-categories-set) the reader has engaged with category preferences (any `cat_*` Tag exists). On expiration, show a Category IAM.
4. If either gap remains, [send a follow-up push](#step-4-follow-up-push-if-data-is-missing) reinforcing what's missing.
5. If the profile is still missing after another day, [send a profile reminder push](#step-5-profile-reminder-push).
6. [Send a final email](#step-6-final-email) branched on `account_type` (upgrade pitch, community welcome, etc.).

***

## Onboarding goals

| Goal                        | Description                                                                                                        |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Complete reader profile     | Log in, create an account, and collect email or SMS Subscriptions.                                                 |
| Set up category preferences | Visit the profile or preference center so `cat_*` Tags get set, enabling targeted broadcasts by topic.             |
| (Optional) Confirm email    | If running [double opt-in](./double-opt-in-email) in parallel, gate every email step on `confirmed_opt_in = true`. |

## Prerequisites

Work through the [News and media strategies implementation roadmap](./news-and-media-industry#implementation-roadmap) before building this Journey. The strategy hub defines the data foundation; this page implements one specific Journey on top of it.

**Required:**

* Familiarity with [Journeys](./journeys-overview) concepts — entry/exit rules, [Wait Until](./journeys-actions#wait-until), and [Yes/No branch](./journeys-actions#yesno-branch).
* An active OneSignal app with at least the data foundation from [News and media strategies](./news-and-media-industry) — `account_type` and the `cat_*` category Tags.
* A [Category Prompt](./permission-requests) or your own category-selection UI on the site to capture the `cat_*` Tags.
* A [preference center](./preference-center) page on your site for IAMs and emails to deep-link to. See [Deep linking](./deep-linking) for the configuration.

**Recommended:**

* The [confirmed opt-in Journey](./double-opt-in-email). When run in parallel, this Welcome Journey can gate every email step on `confirmed_opt_in = true` so unconfirmed addresses don't receive marketing email.
* An [HTML in-app message template](./in-app-html-templates#checklist-survey) for the Category IAM. The HTML format lets readers change category preferences inline without leaving the app.

## Journey configuration

### Required data

| Type | Name                                                                | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ---- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tag  | `account_type`                                                      | Values: `free` / `metered` / `paid` / `lapsed`. Set this Tag **only** on identified users — readers who have an External ID and a completed profile (logged in or registered). Do not set it on anonymous visitors. Existence gates the Profile setup IAM and the profile-reminder push; the Tag's value drives the final-email branch.                                                                                                            |
| Tag  | `cat_*` (one per category, e.g., `cat_breaking_news`, `cat_sports`) | Set these Tags **only** when the reader visits your profile or preference center page — not before. The default value at that point is your call: use `0` for an explicit opt-in model (reader must tick to receive) or `1` for an opt-out model (all categories enabled by default). The "Has selected categories" segment then matches whenever any `cat_*` Tag exists, regardless of value, since existence proves the reader visited the page. |
| Tag  | `confirmed_opt_in`                                                  | *Optional.* `true` if the reader has confirmed their email via the [double opt-in Journey](./double-opt-in-email). Used as a Yes/No gate before each email step.                                                                                                                                                                                                                                                                                   |

### Journey segments

Define these once and reuse them across the Journey steps.

**Has profile:**

* Name: "Has profile"
* Filter: `account_type` **exists**

A reader matches whenever `account_type` is set to any value (`free`, `metered`, `paid`, or `lapsed`). This Tag should only be set on identified users with an External ID, this segment effectively means "has logged in or registered" — anonymous visitors should never match.

**Has selected categories:**

* Name: "Has selected categories"
* Filters: `cat_breaking_news` **exists**

A reader matches as soon as any `cat_*` Tag is present on their record — i.e., they've visited the profile or preference center page where category preferences are captured. Whether the Tag's value is `0` or `1` doesn't matter for this gate; the reader has already made their choice. Update this segment whenever you add a new category to your data model.

**Fully onboarded:**

* Name: "Fully onboarded"
* Filters: `account_type` **exists** **AND** `cat_breaking_news` **exists**

Used by Step 4's Yes/No branch — readers in this segment skip the follow-up push.

### Journey templates

These templates are starting points — clone, edit, and re-use them in your own Journey. They use [Liquid syntax](./using-liquid-syntax) for personalization against `first_name`, `account_type`, `favorite_section`, and `metered_articles_remaining`.

#### Email templates

Two emails carry the long-form moments of the Journey — a welcome at entry and a final cross-sell at the end. Both skip automatically when the reader has no email Subscription, so the IAMs, pushes, and gap checks still drive the rest of the flow.

**Email 1 — Welcome (immediate)**

*Purpose:* Introduce the publication, getting started in the app, and the community, plus what to expect from the Journey.

*Suggested subject:* Welcome to OneSignal News, `{{ first_name | default: 'reader' }}`

*Content outline:*

* A short welcome and thank-you for opting in.
* A **getting started** mini-section — 2–3 things the reader can do next: pick categories, follow newsletters, install the app, log in or create an account.
* A **manage your topics** CTA that deep-links to your preference center.
* Links to your social and community channels (Discord, X, YouTube) so they can follow along outside the app.

**Email 2 — Final**

*Purpose:* Cross-sell other channels and surfaces, branched by `account_type`. The closing email of the Journey.

Branch the content with Liquid (or send conditional templates from a Yes/No branch in the Journey itself):

| `account_type` | Email 2 angle                                                                                                                                           |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Not set        | Account creation pitch with social proof.                                                                                                               |
| `free`         | Upgrade pitch — feature comparison, free trial offer.                                                                                                   |
| `metered`      | Urgency-led upsell — "You're `{{ metered_articles_remaining }}` articles away from your limit."                                                         |
| `paid`         | Community welcome, app download (if web reader), advanced preference features.                                                                          |
| `lapsed`       | Win-back offer with renewal-specific incentive. Consider routing to a [dedicated win-back Journey](./news-and-media-industry#journey-examples) instead. |

#### Push templates

Two pushes drive the gap-reminder steps. Pushes skip automatically for readers without a push Subscription, so email-only and SMS-only readers still progress through the rest of the flow.

**Push 1 — Reinforce (gap-driven)**

*Purpose:* Catch readers who haven't completed their profile or picked categories. A single template that addresses both gaps generically.

*Suggested title:* Finish setting up your OneSignal News experience

*Suggested body:* You're a few taps away from a personalized news feed. Pick your topics or finish your profile.

*Launch URL:* Deep-link to your preference center.

**Push 2 — Profile reminder**

*Purpose:* Nudge readers who still haven't created a profile a day after Push 1. Sent only when `account_type` is still missing.

*Suggested title:* Save your spot, `{{ first_name | default: 'reader' }}`

*Suggested body:* Create an account to sync your reading list, get personalized news, and pick up where you left off on any device.

*Launch URL:* Deep-link to your auth flow (log in or create an account).

#### In-app message templates

Two IAMs nudge readers who arrive at a Wait Until expiration branch. IAMs are queued by the Journey step and display the next time the reader opens the app or site.

**Profile setup IAM**

*Purpose:* Convert anonymous readers into authenticated profiles.

A standard IAM with a "Log in or create an account" CTA that deep-links to the customer's auth flow. Keep copy short — one benefit ("personalized news, saved articles, sync across devices") plus the CTA.

**Category IAM**

*Purpose:* Capture category preferences from readers who haven't selected any.

Two implementation options:

* **HTML IAM with inline form.** Use the [In-App HTML Templates checklist/survey example](./in-app-html-templates#checklist-survey) as a starting point. Render checkboxes for each category; on submit, set the matching `cat_*` Tag to `1`. Highest conversion because the reader doesn't leave the app.
* **Simple IAM with deep-link.** A single CTA that deep-links to a [preference center](./preference-center) page that re-triggers the Category Prompt or shows your custom category UI. Easier to build but adds friction.

The Category Prompt itself can't be triggered from a Journey IAM directly — Journeys can't run client-side prompts. Either render the form inline (HTML IAM), or deep-link to a page that triggers the prompt client-side.

### Journey settings

**Entry rules:**

* Audience: **All users**.
* Future additions only: **Checked** — must stay checked so existing users aren't bulk-enrolled when the Journey is set live.

**Exit rules:**

* Default — when the reader moves through the entire Journey.

**Re-entry rules:** No — the reader can receive this Journey only once.

***

## Journey steps

The Journey has 6 sequential steps. Each email step (Steps 1 and 6) is preceded by a Yes/No on `confirmed_opt_in = true` if you're running [double opt-in](./double-opt-in-email) in parallel. The push steps (Steps 4 and 5) don't need that gate — pushes don't require email confirmation.

### Step 1. Welcome email

<Steps>
  <Step title="Yes/No: confirmed_opt_in = true (optional)">
    Skip this branch if you're not running [double opt-in](./double-opt-in-email).

    **Setup:** Yes/No branch on segment membership for "Confirmed opt-in" (filter: `confirmed_opt_in = true`).

    * **Yes →** continue to the email step.
    * **No →** skip the email and rejoin the main flow at Step 2. The parallel double-opt-in Journey continues moving the reader toward confirmation; this Journey just refuses to send marketing email until they're confirmed.
  </Step>

  <Step title="Email: Email 1 — Welcome">
    Send the welcome email. Skipped automatically by OneSignal if the reader has no email Subscription.
  </Step>
</Steps>

### Step 2. Wait Until profile set

<Steps>
  <Step title="Wait Until: in segment &#x22;Has profile&#x22;">
    **Condition:** the reader is in the **Has profile** segment (`account_type` exists).

    **Expiration:** **24 hours**.

    * **Event branch (segment matched):** silent. Continue to Step 3.
    * **Expiration branch (24h, no profile):** continue to the next step.

    A reader who already has a profile when they reach this step matches the condition immediately and skips straight to Step 3 — no IAM is queued.
  </Step>

  <Step title="In-App Message: Profile setup IAM (expiration branch only)">
    Display the Profile setup IAM. The IAM is queued by the Journey step and renders the next time the reader opens the app or site, deep-linking to the auth flow.

    After this step, the expiration branch rejoins the main flow at Step 3.
  </Step>
</Steps>

### Step 3. Wait Until categories set

<Steps>
  <Step title="Wait Until: in segment &#x22;Has selected categories&#x22;">
    **Condition:** the reader is in the **Has selected categories** segment (any `cat_*` Tag exists).

    **Expiration:** **24 hours**.

    * **Event branch (segment matched):** silent. Continue to Step 4.
    * **Expiration branch (24h, no categories):** continue to the next step.
  </Step>

  <Step title="In-App Message: Category IAM (expiration branch only)">
    Display the Category IAM (HTML form or preference-center deep-link). After this step, the expiration branch rejoins the main flow at Step 4.
  </Step>
</Steps>

### Step 4. Follow-up push (if data is missing)

<Steps>
  <Step title="Yes/No: in segment &#x22;Fully onboarded&#x22;">
    **Setup:** Yes/No branch on the **Fully onboarded** segment (has profile AND has selected categories).

    * **Yes (fully onboarded):** skip the push and continue to Step 5.
    * **No (still missing profile or categories):** continue to the push step.
  </Step>

  <Step title="Push: Push 1 — Reinforce">
    Send the gap-reminder push deep-linked to your preference center. Skipped automatically if the reader has no push Subscription.

    No `confirmed_opt_in` gate is needed — that gate is for marketing email only.
  </Step>
</Steps>

### Step 5. Profile reminder push

<Steps>
  <Step title="Wait: 1 day">
    A simple [Wait](./journeys-actions#wait) step that gives the reader a day to act on Push 1 before the next nudge.
  </Step>

  <Step title="Yes/No: in segment &#x22;Has profile&#x22;">
    **Setup:** Yes/No branch on the **Has profile** segment (`account_type` exists).

    * **Yes (has profile):** skip the push and continue to Step 6.
    * **No (profile still missing):** continue to the push step.
  </Step>

  <Step title="Push: Push 2 — Profile reminder">
    Send the profile-reminder push deep-linked to your auth flow. Skipped automatically if the reader has no push Subscription.

    This step intentionally only checks for profile, not categories — readers without a profile are the highest-value gap to close, and a third push would risk fatigue.
  </Step>
</Steps>

### Step 6. Final email

<Steps>
  <Step title="Yes/No: confirmed_opt_in = true (optional)">
    Same gate as Step 1. Skip if not running double opt-in.
  </Step>

  <Step title="Email: Email 2 — Final">
    Send the final email. Branch content on `account_type` (Liquid `{% case account_type %}` blocks or per-segment templates). See [Email 2 — Final](#email-templates) above for the per-status copy angle.
  </Step>
</Steps>

***

## Best practices

* **Don't compete with editorial sends.** Breaking news goes out as one-time dashboard or API campaigns to category segments (`cat_breaking_news = 1`), not as Journey messages. The Welcome Journey only sends meta messages — welcome, profile/category nudges, and the final upgrade pitch. If you ever feel tempted to add an editorial-style push to this Journey, route it through the [Breaking news broadcasts](./news-and-media-industry#journey-examples) flow instead.
* **Set `cat_*` Tags only when the reader visits your profile or preference center page.** The presence of any `cat_*` Tag is what the segment uses to decide "this reader has seen and made a choice" — Tags shouldn't exist before then. The default value (`0` for opt-in, `1` for opt-out) is up to you and depends on whether you want readers to tick boxes to receive each category or untick to remove them.
* **Update the "Has selected categories" segment whenever you add a new category.** Each `cat_*` Tag has to be OR'd into the segment manually. Document the segment alongside your category list so it doesn't drift.
* **Gate every email step on `confirmed_opt_in = true` if you run double opt-in.** A reader who hasn't confirmed should never get marketing email. The IAMs and gap checks still run for them — only the emails skip.
* **Keep IAMs short.** The Profile and Category IAMs each serve one job. Don't bundle multiple CTAs into either; readers about to convert on a single ask are derailed by a second one.
* **Set a global frequency cap.** Editorial sends will reach readers in the same few days as this Journey. A cap on the segment side (e.g., max one push per reader per 4 hours) prevents the editor's send and any incidental Journey nudges from piling up.
* **Lapsed subscribers can stay in the entry rule** ("All users, future additions only"), but the Email 2 `lapsed` branch is a stopgap. For most teams, a [dedicated win-back Journey](./news-and-media-industry#journey-examples) handles lapsed subscribers better than a final touch tucked inside the welcome flow.

***

## FAQ

### Why doesn't this Journey send breaking news pushes?

Breaking news is editorially driven and time-sensitive — sent as one-time dashboard or API campaigns to category segments (`cat_breaking_news = 1`), not as Journey messages. Mixing editorial content into this Journey would either delay breaking news (waiting on the Journey schedule) or compete with the editor's manual send. Keep the two responsibilities separate.

### What happens to readers without an email Subscription?

The two email steps (welcome and final) skip automatically — OneSignal won't send an email to a reader who has no email channel. The pushes, IAMs, and Wait Until steps still run, so push-only and SMS-only readers still get the gap-driven nudges.

### What if the reader has email but no push?

Welcome and final emails still send. The two follow-up pushes skip automatically because the reader has no push Subscription, and the IAMs never display because the reader has no app or site session for them to render in. The Journey effectively becomes an email-only flow for this reader.

### What is the Wait Until step actually checking?

Wait Until listens for the reader to enter the configured segment. The instant they do, the event branch fires and the Journey continues. If 24 hours pass without the segment matching, the expiration branch fires instead. A reader who already qualifies when they reach the step progresses immediately — no IAM is queued.

### How do I add a new category?

Three steps:

1. Add a new `cat_<category>` Tag to your data model. The Tag is set on a reader's record the next time they visit your profile or preference center page — match the default value (`0` for opt-in, `1` for opt-out) to your other categories so existing readers get a consistent experience.
2. Add the category to your [Category Prompt](./permission-requests) or custom category UI.
3. Update the **Has selected categories** and **Fully onboarded** segments to OR in the new Tag (`cat_<category>` exists). Every step using those segments picks up the change automatically.

### Should I run this alongside the double-opt-in Journey?

Yes if you collect email and want CAN-SPAM / GDPR-aligned consent. Add the [confirmed opt-in Journey](./double-opt-in-email) in parallel, gated on the same audience. This Welcome Journey then checks `confirmed_opt_in = true` before each email step so unconfirmed addresses never receive marketing email.

### Why is the entry rule "All users" instead of a more specific segment?

This Journey is gap-driven, not entry-segmented. Every reader is checked at each step against whether they've completed the corresponding action; readers who arrived already set up just pass through silently. **Future additions only** still prevents bulk-enrolling existing users when the Journey is set live.

### How long does the Journey last?

Roughly 3 days from entry. Step 1 fires immediately, Steps 2 and 3 each have a 24-hour Wait Until window, Step 4 (follow-up push) follows immediately, Step 5 waits 1 day for the profile-reminder push, and Step 6 (final email) sends right after.

## Related pages

<Columns cols={2}>
  <Card title="News and media strategies" icon="newspaper" href="./news-and-media-industry">
    Strategy hub: External IDs, category Tags, Custom Events, segments, and Journey patterns for news and media.
  </Card>

  <Card title="Confirmed opt-in for email" icon="envelope-circle-check" href="./double-opt-in-email">
    Run the double opt-in Journey in parallel and gate this Journey's email steps on `confirmed_opt_in = true`.
  </Card>

  <Card title="Permission requests" icon="bell" href="./permission-requests">
    Configure the Category Prompt that captures `cat_*` Tags before this Journey starts.
  </Card>

  <Card title="In-App HTML templates" icon="code" href="./in-app-html-templates#checklist-survey">
    Build the inline category-selection form used by the Category IAM.
  </Card>

  <Card title="Preference center" icon="sliders" href="./preference-center">
    The destination for emails and IAMs that need richer settings (frequency, quiet hours, newsletters).
  </Card>

  <Card title="Deep linking" icon="arrow-up-right-from-square" href="./deep-linking">
    Deep-link from emails and IAMs to specific pages on your site or app.
  </Card>
</Columns>
