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

# Send your first push notification

> Send a test notification to one device, then write and send a push campaign, and read what Firebase accepted it means.

export const Screenshot = ({id, src, srcDark, alt, caption}) => {
  if (!src) {
    return <Placeholder id={id} kind="screenshot" label="Screenshot coming soon" description={alt} icon={<ImageIcon />} />;
  }
  return <figure className="brd-media" data-media-id={id}>
      <img className="brd-media-frame block dark:hidden" src={src} alt={alt} />
      <img className="brd-media-frame hidden dark:block" src={srcDark || src} alt={alt} />
      {caption && <figcaption className="brd-media-caption">{caption}</figcaption>}
    </figure>;
};

By the end of this page you'll have sent a test notification to your own device, then a push
campaign, and you'll know where to follow what happened to it.

<Screenshot id="ss-push-send-your-first-push-hero-push-block" alt="The push block in the campaign composer with its Title, Body, Apps and Priority fields filled in and a device count beside the audience" />

<Info>
  **Before you start**, you need:

  * An app showing **Active** in **Channels > Push**. See
    [Connect Firebase](/channels/push/connect-firebase).
  * A device token from a test device running your app, for the test send.
  * For a campaign, contacts with an active device registered against that app. See
    [Register device tokens](/channels/push/register-device-tokens).
</Info>

## Send a test first

You can test at two levels, and neither test is saved to a contact.

* **An app:** on the **Apps** tab, select **Send a test** (the paper-plane icon) on an **Active**
  app and paste a device token. See [Connect Firebase](/channels/push/connect-firebase).
* **A campaign:** in the campaign's **Send a test** dialog, pick a **Push app** and paste a device
  token. See [Create and send a campaign](/campaigns/create-a-campaign).

Tests are sent in the background, and the result appears in the dialog once Firebase has answered.
**Accepted by the provider** means Firebase took the notification for delivery, so check the device
itself to confirm it arrived.

## Send a campaign

<Steps>
  <Step title="Create a campaign">
    Go to **Campaigns** and create a campaign. Give it a **Campaign name**, and under **Channels**,
    select **Push**. See [Create a campaign](/campaigns/create-a-campaign).
  </Step>

  <Step title="Choose the audience">
    Select **Choose audience** and pick **Lists**, **Segments** or individual **Contacts**. Only
    contacts with an active device are reachable, and Brudcast shows the push reach beside the
    audience.

    For your first campaign, choose only your own contact, so the first notification goes to your
    own device.
  </Step>

  <Step title="Pick the apps">
    Leave **Apps** on every active app, or name the ones to send through. A device is reached only
    through the app it was registered against.
  </Step>

  <Step title="Write the notification">
    Fill in **Title** and **Body**. Both are required, and both accept merge tags. Keep them short,
    because devices cut long text on the lock screen. The options are covered in
    [Write the notification](#write-the-notification) below.

    <Screenshot id="ss-push-send-your-first-push-04-title-body" alt="The push Title and Body fields filled in, with a merge tag in the title and a lock-screen preview beside them" />
  </Step>

  <Step title="Clear the send checklist">
    **Before you send** lists anything that would stop the campaign. See
    [Send checklist](/campaigns/send-checklist).
  </Step>

  <Step title="Send">
    Select **Send** to send now, or schedule it. See
    [Create and send a campaign](/campaigns/create-a-campaign).
  </Step>
</Steps>

## Write the notification

A campaign's push content has a **Title** and a **Body**, both required, plus an optional
**Image URL** and **Click URL**.

| Option            | What it does                                                                                |
| ----------------- | ------------------------------------------------------------------------------------------- |
| **Apps**          | The apps the campaign sends through. By default, every active app                           |
| **Data**          | Key and value pairs your app reads when the notification arrives. Recipients don't see them |
| **Expires after** | How long Firebase keeps trying a device that is offline. 1 day by default                   |
| **Priority**      | **Normal** saves battery. **High** wakes the device straight away                           |

**Click URL** is sent to your app in the notification's data as `click_url`, unless you set a
`click_url` data key yourself. On Android and iOS your app decides what to do with it. On the web the
browser opens it when the notification is clicked, as long as it starts with `https://`.

**Data** has limits, and a message that breaks them is refused:

| Rule                  | Limit                                                                                              |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| Keys per notification | 20                                                                                                 |
| Key length            | 64 characters                                                                                      |
| Value length          | 1,024 characters                                                                                   |
| Reserved keys         | `from`, `notification`, `message_type`, and any key starting with `google.` or `gcm.`, in any case |

Reserved keys are refused when you save the campaign, because Firebase rejects any message carrying
one, so a single reserved key would make every device in the campaign fail.

**Expires after** offers **Only if the device is reachable now** (no retrying, so an offline device
never gets it), **1 hour**, **6 hours**, **1 day (default)**, **3 days**, **1 week**, and **4 weeks**,
which is the maximum at 28 days.

The campaign blocks are covered in
[Write content for each channel](/campaigns/write-content-per-channel).

## What happens next

Before a push campaign sends, Brudcast checks that:

* the push content has a title and a body,
* at least one of the campaign's apps is **Active**, and every app you picked is, and
* the audience has at least one active device registered against those apps.

A contact is reachable on push when it has an active device registered against one of the campaign's
apps. Each device gets its own notification and counts as one notification, so a contact with a phone
and a tablet counts twice.

Campaign results label push **Accepted** where email says **Delivered**, because Firebase confirms
only that it took the notification. See
[Accepted, not delivered](/channels/push/overview#accepted-not-delivered) and
[Campaign results](/campaigns/results).

## Troubleshooting

### Apps and credentials

<AccordionGroup>
  <Accordion title="The app shows Credential invalid" icon="circle-alert">
    **Why:** Firebase rejected the service account key, either during validation or during a send,
    and its reason is shown under the status in the **Apps** table. The usual causes are a service
    account without the **Firebase Cloud Messaging API Admin** role, a key that was deleted in
    Google Cloud, or the **Firebase Cloud Messaging API** being turned off for the project.

    **Fix:** correct the role, and check that the **Firebase Cloud Messaging API** is enabled under
    **APIs & Services** in the Google Cloud console. Then select **Validate again** in the app's
    **More actions** menu, or use **Replace credential** with a new key. See
    [Connect Firebase](/channels/push/connect-firebase).
  </Accordion>

  <Accordion title="The app stays on Validating" icon="circle-alert">
    **Why:** validation usually takes a few seconds. Much longer, and the check may not have
    completed.

    **Fix:** select **Validate again** in the app's **More actions** menu. If nothing changes, email
    [support@brudcast.com](mailto:support@brudcast.com).
  </Accordion>

  <Accordion title="“Subscribe to Push”" icon="circle-alert">
    **Why:** your organization has no Push subscription, so apps can't be added.

    **Fix:** pick a Push plan in **Billing & Plans**. See
    [Plans and subscriptions](/billing/plans-and-subscriptions).
  </Accordion>
</AccordionGroup>

### Campaigns that won't send

<AccordionGroup>
  <Accordion title="“No active push apps yet.”" icon="circle-alert">
    **Why:** no app has the status **Active**, so the campaign has nothing to send through.

    **Fix:** [connect an app](/channels/push/connect-firebase), or fix one showing
    **Credential invalid**.
  </Accordion>

  <Accordion title="“Push has no app selected to send from.”" icon="circle-alert">
    **Why:** the send checklist found no app for the campaign's push block.

    **Fix:** choose apps in **Apps**, or leave **All active apps**.
  </Accordion>

  <Accordion title="“The notification title or body is missing.”" icon="circle-alert">
    **Why:** the send checklist found an empty **Title** or **Body**.

    **Fix:** fill in both. Merge tags alone can leave a field empty for some contacts, so add fixed
    text as well.
  </Accordion>

  <Accordion title="“The provider rejected the message.”" icon="circle-alert">
    **Why:** Firebase refused the notification itself. In a campaign this stops the push part at the
    first failure.

    **Fix:** check the data keys and the **Image URL** against the limits above.
  </Accordion>

  <Accordion title="“The provider is rate limiting this app. Try again shortly.”" icon="circle-alert">
    **Why:** Firebase is limiting how fast this project can send.

    **Fix:** wait and try again.
  </Accordion>
</AccordionGroup>

### Devices and delivery

<AccordionGroup>
  <Accordion title="Contacts have tokens, but the campaign reached none of them" icon="circle-alert">
    **Why:** a device is reached only through the app it was registered against, and only while its
    status is `active`. The tokens may belong to an app you didn't pick, the devices may be
    `inactive` or `expired`, their app may be **Disabled**, or the contacts may not be in the
    audience.

    **Fix:** check the devices on a few contacts and compare their app with the campaign's **Apps**
    field. See [Register device tokens](/channels/push/register-device-tokens).
  </Accordion>

  <Accordion title="“The device token is not registered with this app.”" icon="circle-alert">
    **Why:** Firebase doesn't recognize the token for this project. The app may have been
    uninstalled, Firebase may have replaced the token, or the token belongs to another project.

    **Fix:** register a fresh token from the device. During campaigns Brudcast expires tokens like
    this by itself and sends the `push.token_invalidated` webhook.
  </Accordion>

  <Accordion title="The test says Accepted by the provider, but nothing appears on the device" icon="circle-alert">
    **Why:** Firebase accepted the notification. It doesn't confirm that the notification reached the
    device.

    **Fix:** check that the app has permission to show notifications on the device, and that the
    token came from an app in the same Firebase project.
  </Accordion>
</AccordionGroup>

## Related

<Columns cols={2}>
  <Card title="Push overview" icon="bell" href="/channels/push/overview">
    How apps, devices and campaigns fit together.
  </Card>

  <Card title="Register device tokens" icon="smartphone" href="/channels/push/register-device-tokens">
    Store each device's token on its contact.
  </Card>

  <Card title="Write content for each channel" icon="layers" href="/campaigns/write-content-per-channel">
    Send push alongside email and SMS.
  </Card>

  <Card title="Campaign results" icon="chart-column" href="/campaigns/results">
    Follow what happened after you send.
  </Card>
</Columns>
