# A2U (App-to-User) API


The A2U (App-to-User) API lets you send notifications directly from your backend server

A2U notifications are one of the most effective re-engagement tools available because they reach players where they already are: on Facebook. A well-timed, relevant notification can bring a lapsed player back into your game at exactly the right moment.

This guide covers what A2U notifications are, how they differ from other notification types, API details, targeting and segmentation, notification templates, rate limits, policies, and best practices.

## What Are A2U Notifications?

A2U notifications are server-initiated messages from your game to specific players. Unlike [Custom Updates](https://developers.facebook.com/documentation/games/retain/custom-updates) (which are sent from within the game client during a play session) or [Game Updates via Messenger](https://developers.facebook.com/documentation/games/retain/notifications/game-updates-messenger) (which are delivered through Messenger), A2U notifications are:

- **Sent from your backend server** using the Facebook Graph API
- **Delivered as Facebook notifications** (not Messenger messages)
- **Triggered by server-side logic** (not by in-game player actions)
- **Targeted to specific players** based on their player ID

### How A2U Differs from Other Channels

| Aspect | A2U API | Custom Updates | Game Updates (Messenger) |
|--------|---------|---------------|--------------------------|
| **Origin** | Your backend server | Game client (SDK) | Your backend server (Messenger API) |
| **Delivery** | Facebook notification tray | In-game conversation/context | Messenger inbox |
| **Trigger** | Server-side event or schedule | Player action in-game | Server-side event or schedule |
| **Player action** | Taps notification, opens game | Taps update in conversation | Taps message in Messenger |
| **Content** | Text + optional image | Rich image, text, CTA, data | Rich templates, images, buttons |
| **Setup** | Graph API integration | SDK call | Messenger bot + webhook |

## Player Opt-In

Before you can send A2U notifications to a player, the player must opt in. The opt-in flow is handled through the Instant Games SDK.

### Requesting Opt-In

Use the SDK to check whether the player has opted in and to request opt-in if they have not:

```javascript
async function requestNotificationOptIn() {
  try {
    // Check current opt-in status
    const canSubscribe = await FBInstant.player.canSubscribeBotAsync();

    if (canSubscribe) {
      // Player has not opted in yet -- request opt-in
      await FBInstant.player.subscribeBotAsync();
      console.log('Player opted in for notifications!');
      return true;
    } else {
      console.log('Player has already opted in or opt-in is not available');
      return false;
    }
  } catch (error) {
    console.error('Opt-in failed:', error);
    return false;
  }
}
```

### When to Request Opt-In

Timing is critical for opt-in requests. Do not ask immediately on first launch -- the player has not yet experienced your game and has no reason to say yes. Instead, request opt-in at a moment when the player has had a positive experience and can understand the value:

- After the player completes their first few levels or rounds
- After the player achieves a personal best
- After explaining what notifications they will receive (e.g., "Get notified when a friend beats your score")
- When the player is about to leave a session (e.g., "Want to be notified when your energy refills?")

## Sending Notifications

Once a player has opted in, you can send notifications from your backend server using the Facebook Graph API.

### API Endpoint

```
POST https://graph.facebook.com/v18.0/{player_id}/notifications
```

### Request Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `access_token` | `string` | Yes | Your app's access token. |
| `href` | `string` | Yes | A relative path that is appended to your game's URL when the player taps the notification. Use this for deep linking. |
| `template` | `string` | Yes | The notification message text. Supports a `@[{player_id}]` token that is replaced with the player's name. |
| `ref` | `string` | No | A custom reference string that is passed to your game when the player opens it from the notification. Useful for tracking and deep linking. |

### Basic Example

```javascript
// Node.js example using fetch
async function sendNotification(playerId, message, deepLink) {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${playerId}/notifications`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        access_token: APP_ACCESS_TOKEN,
        href: deepLink || '',
        template: message,
      }),
    }
  );

  const data = await response.json();

  if (data.success) {
    console.log('Notification sent successfully');
  } else {
    console.error('Notification failed:', data.error);
  }

  return data;
}

// Example usage
sendNotification(
  'player_12345',
  'Your friend @[player_67890] just beat your high score! Can you take it back?',
  '/challenge?ref=score_beat'
);
```

### Deep Linking with href

The `href` parameter lets you deep-link the player to a specific screen or action in your game. When the player taps the notification, they are taken to your game's URL with the `href` value appended.

In your game client, you can read the entry point data to handle deep links:

```javascript
async function handleNotificationEntry() {
  await FBInstant.initializeAsync();

  const entryPointData = FBInstant.getEntryPointData();
  const entryPoint = FBInstant.getEntryPointAsync
    ? await FBInstant.getEntryPointAsync()
    : null;

  if (entryPointData && entryPointData.ref) {
    switch (entryPointData.ref) {
      case 'score_beat':
        showLeaderboard();
        break;
      case 'daily_reward':
        showDailyRewardScreen();
        break;
      case 'tournament_start':
        showTournamentLobby();
        break;
      default:
        showMainMenu();
    }
  } else {
    showMainMenu();
  }

  await FBInstant.startGameAsync();
}
```

## Targeting and Segmentation

A2U notifications are most effective when they are relevant to the specific player receiving them. Sending the same generic message to all players is wasteful and will lead to high opt-out rates. Instead, segment your player base and send targeted notifications.

### Segmentation Strategies

- **By activity level:**
  - **Active players (played today):** Notify about new tournaments, limited-time events, or friend activity
  - **Recently lapsed (2-3 days inactive):** "Your daily streak is about to reset!" or "Your energy is full"
  - **Lapsed (7+ days inactive):** "We miss you! Here is a special comeback bonus"

- **By game state:**
  - Players stuck on a difficult level: "New power-ups available to help you past Level 12!"
  - Players with expiring resources: "Your 3 bonus lives expire in 2 hours"
  - Players approaching a milestone: "You are 50 points away from the weekly leaderboard top 10!"

- **By social context:**
  - Friends who beat each other's scores: "Sarah just scored 2,450 and passed you!"
  - Friends who joined a tournament: "Mike just joined the Weekend Challenge. Join now!"
  - Friends who started playing: "Your friend Alex started playing! Say hello."

### Example: Segmented Notification System

```javascript
async function sendSegmentedNotifications(players) {
  for (const player of players) {
    const daysSinceLastPlay = getDaysSinceLastPlay(player);
    const message = getMessageForSegment(player, daysSinceLastPlay);

    if (message) {
      await sendNotification(player.id, message.text, message.deepLink);
      // Add a small delay between sends to avoid rate limiting
      await sleep(100);
    }
  }
}

function getMessageForSegment(player, daysSinceLastPlay) {
  if (daysSinceLastPlay === 0) {
    // Player played today -- check for friend score beats
    if (player.friendBeatScore) {
      return {
        text: `@[${player.friendId}] just beat your score of ${player.lastScore}!`,
        deepLink: '/leaderboard?ref=score_beat',
      };
    }
    return null; // Do not notify active players without a reason
  }

  if (daysSinceLastPlay <= 3) {
    return {
      text: 'Your daily reward is waiting! Log in to claim it before it expires.',
      deepLink: '/rewards?ref=daily_reward',
    };
  }

  if (daysSinceLastPlay <= 7) {
    return {
      text: 'A new weekly tournament just started. Compete with friends for the top spot!',
      deepLink: '/tournament?ref=weekly_tournament',
    };
  }

  if (daysSinceLastPlay <= 30) {
    return {
      text: 'It has been a while! We have added new levels and features. Come check them out!',
      deepLink: '/whatsnew?ref=comeback',
    };
  }

  return null; // Do not notify players who have been gone more than 30 days
}
```

## Notification Templates

Templates help you maintain consistent, high-quality notification messaging. Define your templates with placeholders that get filled in with player-specific data.

### Example Templates

| Template Name | Message | When to Send |
|--------------|---------|-------------|
| `score_beat` | `@[{friend_id}] just scored {score} and passed you on the leaderboard!` | When a friend surpasses the player's score |
| `daily_reward` | `Your daily reward is ready! Log in to claim it.` | When a daily reward becomes available |
| `tournament_start` | `A new tournament just started! Compete with friends for the top spot.` | When a new tournament begins |
| `energy_full` | `Your energy is fully recharged! Time to play.` | When the player's energy refills |
| `streak_warning` | `Your {streak_count}-day streak is about to end! Play now to keep it alive.` | When a streak is about to expire |
| `friend_joined` | `Your friend @[{friend_id}] just started playing! Say hello.` | When a friend starts playing the game |

## Rate Limits and Policies

### Rate Limits

Facebook enforces rate limits on A2U notifications to protect the player experience:

- **Per-player limits:** You can send a limited number of notifications to each individual player within a given time window (typically a few per day). Exceeding this limit will result in the notification being rejected.
- **Per-app limits:** Your app has an overall daily notification budget across all players. This budget scales with your app's active user count.
- **Throttling:** If you send a large volume of notifications in a short period, the API may throttle your requests. Implement backoff logic and spread sends over time.

### Content Policies

- **Relevance:** Notifications must be relevant to the player's game activity. Do not send marketing messages, promotional content for other apps, or unrelated information.
- **Accuracy:** Notification content must be truthful and accurately represent what the player will find when they open the game.
- **No deception:** Do not use misleading language to trick players into opening the game.
- **Compliance:** All notifications must comply with Facebook's [Platform Policies](https://developers.facebook.com/policy/) and [Advertising Policies](https://www.facebook.com/policies/ads/).

### Consequences of Policy Violations

If your app is found to be violating notification policies:
- Notifications may be throttled or disabled for your app
- Your app may be flagged for review
- In severe cases, your app may be suspended from the platform

### Error Handling

```javascript
async function sendNotificationWithErrorHandling(playerId, template, href) {
  try {
    const response = await fetch(
      `https://graph.facebook.com/v18.0/${playerId}/notifications`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          access_token: APP_ACCESS_TOKEN,
          template: template,
          href: href,
        }),
      }
    );

    const data = await response.json();

    if (data.error) {
      switch (data.error.code) {
        case 4:
          console.warn('Rate limited. Retry later.');
          break;
        case 100:
          console.error('Invalid parameter:', data.error.message);
          break;
        case 200:
          console.warn('Player has opted out of notifications.');
          // Remove player from notification list
          markPlayerOptedOut(playerId);
          break;
        default:
          console.error('Unknown error:', data.error);
      }
    }

    return data;
  } catch (error) {
    console.error('Network error:', error);
    return null;
  }
}
```

## User information integration in bot messages

In a Network Enabled Zero Permissions (NEZP) environment, you cannot access player profile data (name, photo) directly. Instead, you can use the SDK to create notification content that integrates user information through NEZP overlay views, and then reference that content when sending bot messages via the Graph API.

### Creating the notification

Use `FBInstant.player.createNEZPNotificationContentAsync()` to create reusable notification content that renders an image overlay from your XML/CSS templates, resolves user data (such as profile picture and name) server-side, and stores the result on Meta servers.

```javascript
await FBInstant.player.createNEZPNotificationContentAsync({
  imageOverlayPath: 'ig_views/profile_view.xml',
  pathToCSS: 'ig_views/styles.css',
  initialData: {wordSubmitted: 'APPLE'},
  notificationTitle: '{{FBInstant.player.name}} just took their turn!',
  notificationSubtitle: 'It is your turn now!',
  recipients: ['6719542978151885'],
}).then((notificationContentId) =>
  console.log('Notification content created with ID: ' + notificationContentId)
).catch((error) =>
  console.error('Failed to create notification:', error.code, error.message)
);
```

The `imageOverlayPath` parameter points to an XML overlay view that defines the image layout. The image is rendered in the background so gameplay is uninterrupted. The generated image, notification title, and subtitle are stored on Meta servers.

The API returns a `notification_content_id` that you can use in the Graph API to reference the stored content when sending a bot message.

The `recipients` parameter specifies the player IDs of valid recipients. These players must be part of the current game context.

### Sending the notification

To send a notification using the stored content, provide the `notification_content_id` along with the `player_id` in the Graph API endpoint:

```
POST https://graph.facebook.com/v25.0/{player_id}/notifications
```

The `player_id` must be one of the recipients specified in the original SDK API call.

For the full `createNEZPNotificationContentAsync` API reference, see [FBInstant.player](https://developers.facebook.com/documentation/games/sdk-reference/v8.0/player#createNEZPNotificationContentAsync).

## Next Steps

- **[Notification Best Practices](https://developers.facebook.com/documentation/games/retain/notifications/best-practices)** -- Consolidated best practices across all notification channels.
- **[Notification Guidelines](https://developers.facebook.com/documentation/games/retain/notifications/notification-guidelines)** -- Content formatting and quality criteria for notification messages.
- **[Game Updates via Messenger](https://developers.facebook.com/documentation/games/retain/notifications/game-updates-messenger)** -- Send rich, interactive messages through Messenger.
- **[Notification Service](https://developers.facebook.com/documentation/games/retain/notifications/notification-service)** -- Scheduled notifications through Facebook's infrastructure.
- **[Notifications Overview](https://developers.facebook.com/documentation/games/retain/notifications/overview)** -- Compare all notification channels.
- **[Custom Updates](https://developers.facebook.com/documentation/games/retain/custom-updates)** -- Send in-game updates and messages from the game client.