0Pricing
React Native Academy · บทเรียน

การส่งการแจ้งเตือนผ่าน Expo Push API

ส่งข้อมูลการแจ้งเตือนด้วย POST ไปยัง Expo Push API จากเซิร์ฟเวอร์หรือคำสั่ง curl ระบุโทเค็นอุปกรณ์เป้าหมาย และตรวจสอบการส่งในแดชบอร์ด Expo

การส่งการแจ้งเตือนผ่าน Expo Push API เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

The Expo Push Notification Service

The Expo Push Notification Service (EPNS) is a relay that sits between your server and the platform-specific push gateways (Apple APNs and Google FCM). Instead of integrating with two separate services, you send one HTTP request to Expo's API and it handles the platform differences for you.

EPNS is free for apps using Expo's managed workflow and handles certificate management, token routing, batching, and error reporting. For production apps with high volume you can switch to direct APNs/FCM integration, but EPNS is an excellent starting point for most apps.

The Expo Push API Endpoint

Send a POST request to https://exp.host/--/api/v2/push/send with a JSON body containing one or more notification messages. Each message targets a specific Expo push token and includes the notification content.

The API accepts up to 100 messages per request for efficient batching. Always send from your server, never from the client — the client doesn't know other users' tokens and sending from the client exposes your server logic.

// From your backend server (Node.js example):
const response = await fetch('https://exp.host/--/api/v2/push/send', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'ExponentPushToken[AbCdEfGhIjKl...]',
    title: 'New message',
    body: 'Alice sent you a message!',
  }),
});
const result = await response.json();
console.log(result);

Notification Message Fields

The notification message object supports several fields:

  • to (required) — the Expo push token or array of tokens
  • title — the bold notification title
  • body — the notification message text
  • data — a JSON object with custom payload for the app to read when tapped
  • sound — 'default' to play the device sound
  • badge — integer to set the iOS app icon badge count
  • channelId — Android notification channel ID
const message = {
  to: 'ExponentPushToken[AbCdEfGhIjKl...]',
  sound: 'default',
  title: 'Order Shipped',
  body: 'Your order #1234 is on its way!',
  badge: 1,
  channelId: 'orders',
  data: {
    type: 'order_update',
    orderId: '1234',
    screen: 'OrderDetail',
  },
};

Sending to Multiple Devices

To send the same notification to multiple devices (e.g., a broadcast or a notification to all of a user's devices), pass an array of tokens to the to field. Each token will receive the notification.

For large audiences, chunk your token list into batches of 100 and send a separate API request per batch. The Expo Push API enforces rate limits and batch size limits, so batching is required for scale.

// Send to multiple devices:
const messages = tokens.map((token) => ({
  to: token,
  title: 'New feature available!',
  body: 'Check out what we built for you.',
  data: { screen: 'WhatsNew' },
}));

// Chunk into batches of 100:
const chunks = [];
for (let i = 0; i < messages.length; i += 100) {
  chunks.push(messages.slice(i, i + 100));
}

for (const chunk of chunks) {
  await fetch('https://exp.host/--/api/v2/push/send', {
    method: 'POST',
    body: JSON.stringify(chunk),
  });
}

Using the Expo Server SDK

Instead of making raw HTTP requests, use the official expo-server-sdk npm package in your Node.js backend. It provides chunking, error handling, and receipt checking out of the box. Install it with npm install expo-server-sdk.

The SDK's sendPushNotificationsAsync method handles batching automatically and returns ticket objects you can use to check delivery receipts later. It also validates tokens before sending to avoid wasting API calls on malformed tokens.

// Backend (Node.js):
const { Expo } = require('expo-server-sdk');
const expo = new Expo();

const messages = tokens
  .filter(token => Expo.isExpoPushToken(token))
  .map(token => ({
    to: token,
    title: 'Hello!',
    body: 'This is a push notification',
    data: { type: 'greeting' },
  }));

const chunks = expo.chunkPushNotifications(messages);
const tickets = [];
for (const chunk of chunks) {
  const ticketChunk = await expo.sendPushNotificationsAsync(chunk);
  tickets.push(...ticketChunk);
}

Push Receipts: Confirming Delivery

Sending to the Expo API gives you tickets immediately — they confirm the message was accepted, not that it was delivered. A few minutes later, check receipts to verify actual delivery to APNs/FCM. Use the ticket IDs from the send step to fetch receipts from https://exp.host/--/api/v2/push/getReceipts.

Receipts with status 'error' and code DeviceNotRegistered mean the token is no longer valid — remove it from your database to keep your token list clean and avoid wasting API calls.

// After sending, check receipts (wait ~5 minutes):
const receiptIds = tickets
  .filter(t => t.status === 'ok')
  .map(t => t.id);

const receiptChunks = expo.chunkPushNotificationReceiptIds(receiptIds);
for (const chunk of receiptChunks) {
  const receipts = await expo.getPushNotificationReceiptsAsync(chunk);
  for (const [id, receipt] of Object.entries(receipts)) {
    if (receipt.status === 'error') {
      if (receipt.details.error === 'DeviceNotRegistered') {
        await removeTokenFromDB(id); // clean up
      }
    }
  }
}

Testing Push Notifications

Expo provides a push notification testing tool at https://expo.dev/notifications. Enter your Expo push token and send test notifications directly from the dashboard — no server code required. This is invaluable for testing notification appearance and delivery on a real device.

You can also use a curl command from the terminal to send test notifications. This is faster during development and lets you test arbitrary payloads and data objects without writing server code first.

# Test push from terminal:
curl -H 'Content-Type: application/json' \
  -X POST 'https://exp.host/--/api/v2/push/send' \
  -d '{
    "to": "ExponentPushToken[YOUR_TOKEN_HERE]",
    "title": "Test Notification",
    "body": "Hello from curl!",
    "data": { "test": true }
  }'

# Or use Expo dashboard:
# https://expo.dev/notifications

Scheduling Notifications from the App

Beyond push notifications from a server, you can schedule local notifications from the app itself — they work offline and don't require a server. Use Notifications.scheduleNotificationAsync with a trigger that defines when the notification fires.

Common trigger types: seconds — fire after a delay; date — fire at a specific time; weekly — fire on a specific weekday and time. Local notifications are perfect for reminders, alarms, and scheduled check-ins.

// Schedule a local notification 10 seconds from now:
await Notifications.scheduleNotificationAsync({
  content: {
    title: 'Reminder',
    body: 'Time to review your daily goals!',
    data: { screen: 'Goals' },
  },
  trigger: {
    seconds: 10, // fires after 10 seconds
  },
});

// Schedule for a specific date:
await Notifications.scheduleNotificationAsync({
  content: { title: 'Meeting in 5 minutes', body: 'Team standup' },
  trigger: new Date(Date.now() + 5 * 60 * 1000),
});

Notification Priority and Delivery

Notification priority affects how aggressively the OS delivers a notification. High priority notifications wake up the device screen immediately (used for urgent alerts like messages). Normal priority are batched and delivered when convenient (used for promotional content).

In the Expo Push API, set priority: 'high' for time-sensitive notifications. Be conservative — sending too many high-priority notifications trains users to ignore them, and Apple may deprioritize your app's notifications if abused.

// High priority (message, call, alert):
{
  to: token,
  title: 'Incoming call',
  body: 'Bob is calling you',
  priority: 'high',
  channelId: 'calls',
  data: { screen: 'IncomingCall', callId: 'abc' },
}

// Normal priority (digest, update):
{
  to: token,
  title: 'Weekly summary ready',
  body: 'See how you did this week!',
  priority: 'normal',
  channelId: 'digest',
}

Handling Notification Tap on App Launch

When a user taps a notification and the app is completely closed, the app launches. To navigate to the correct screen based on the notification, read the last notification response on launch using Notifications.getLastNotificationResponseAsync().

Read this early in your app's boot sequence (in App.js or your root navigator) and navigate when the response contains a data.screen payload. This bridges push notifications with deep navigation into your app.

useEffect(() => {
  Notifications.getLastNotificationResponseAsync().then((response) => {
    if (response) {
      const { screen, id } = response.notification.request.content.data;
      if (screen && navigationRef.isReady()) {
        navigationRef.navigate(screen, { id });
      }
    }
  });
}, []);

Canceling and Managing Scheduled Notifications

Cancel a specific scheduled notification with Notifications.cancelScheduledNotificationAsync(identifier), where the identifier is the string returned from scheduleNotificationAsync. Cancel all scheduled notifications with Notifications.cancelAllScheduledNotificationsAsync().

Store notification identifiers in AsyncStorage if you need to cancel them after an app restart — for example, canceling a reminder when the user marks a task as complete.

// Schedule and save identifier:
const id = await Notifications.scheduleNotificationAsync({
  content: { title: 'Take your medicine' },
  trigger: { hour: 9, minute: 0, repeats: true },
});
await AsyncStorage.setItem('medicineReminderNotifId', id);

// Later, cancel it:
const notifId = await AsyncStorage.getItem('medicineReminderNotifId');
if (notifId) {
  await Notifications.cancelScheduledNotificationAsync(notifId);
  await AsyncStorage.removeItem('medicineReminderNotifId');
}

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: the Expo Push API accepts POST requests to exp.host with token, title, body, and data fields to send notifications via APNs/FCM, push receipts confirm actual delivery and DeviceNotRegistered errors signal tokens to delete, and local notifications can be scheduled from the app itself using Notifications.scheduleNotificationAsync with time-based triggers. Next up we handle foreground and background notification events inside the app.

คำถามที่พบบ่อย

บทเรียน “การส่งการแจ้งเตือนผ่าน Expo Push API” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การส่งการแจ้งเตือนผ่าน Expo Push API” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การส่งการแจ้งเตือนผ่าน Expo Push API”

ส่งข้อมูลการแจ้งเตือนด้วย POST ไปยัง Expo Push API จากเซิร์ฟเวอร์หรือคำสั่ง curl ระบุโทเค็นอุปกรณ์เป้าหมาย และตรวจสอบการส่งในแดชบอร์ด Expo คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การส่งการแจ้งเตือนผ่าน Expo Push API” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การขอสิทธิ์และรับโทเค็นพุช
  2. การส่งการแจ้งเตือนผ่าน Expo Push API
  3. การจัดการการแจ้งเตือนขณะอยู่เบื้องหน้าและเบื้องหลัง
  4. ช่องการแจ้งเตือนและเนื้อหาแบบหลากหลาย
← กลับไปที่ React Native Academy