Quick Start: All you need are your Firebase Service Account JSON file and FCM tokens to start testing!
A simple Express-based server for testing push notifications to Android/iOS devices using Firebase Cloud Messaging (FCM).
νκ΅μ΄ λ²μ 보기 (View Korean Version)
- π Simple web interface for sending push notifications
- π± Support for multiple FCM tokens
- π Send multiple messages per token (bulk testing)
- βοΈ Customizable message JSON (notification, data, android/ios specific settings)
- π Detailed response with success/failure counts
- π― Perfect for testing push notification implementations
To use this server, you only need two things:
- Firebase Service Account JSON file - Get it from your Firebase Console
- FCM Device Tokens - Get these from your mobile app
That's it! No complex setup required.
npm install- Go to Firebase Console
- Select your project
- Go to Project Settings > Service Accounts tab
- Click "Generate New Private Key" to download the JSON file
- Save the JSON file securely
Create a .env file in the project root and configure your Firebase credentials using one of the following methods:
Method 1: JSON file path (Recommended for local development)
FIREBASE_SERVICE_ACCOUNT_PATH=./path/to/your-firebase-service-account.jsonMethod 2: Complete JSON as string (Good for deployment)
FIREBASE_SERVICE_ACCOUNT='{"type":"service_account","project_id":"your-project-id","private_key":"-----BEGIN PRIVATE KEY-----\n...","client_email":"firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com",...}'Method 3: Individual fields (Most secure for production)
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYour private key here\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com# Standard mode
npm start
# Development mode (with nodemon)
npm run devThe server will start on http://localhost:3000 (or the PORT specified in your .env file).
- Open your browser and go to
http://localhost:3000 - Enter one or more FCM device tokens
- (Optional) Customize the message JSON
- Set the number of messages to send per token
- Click "Send" button
Step 1: Enter FCM Tokens
- Enter your FCM device tokens (supports multiple tokens)
- Set the number of messages to send per token (default: 10)
- Optionally expand "Customize Message JSON" section to customize your push notification
Step 2: Customize Message (Optional)
- Edit the JSON to customize notification title, body, and data fields
- Use the "FORMAT" button to format your JSON
- Use "RESET TO DEFAULT" to restore the default template
- Use "LOAD EXAMPLE" to see a data-rich example
- Click "SEND" when ready
GET /health
Check if the server and FCM are properly initialized.
Response:
{
"status": "ok",
"fcmInitialized": true,
"timestamp": "2024-01-01T00:00:00.000Z"
}GET /message-template
Returns the default message template used by the server.
POST /push
Content-Type: application/json
Request Body:
{
"tokens": ["token1", "token2"],
"messagesPerToken": 10,
"message": {
"notification": {
"title": "Test Notification",
"body": "This is a test message"
},
"data": {
"key1": "value1",
"key2": "value2"
},
"android": {
"priority": "high",
"notification": {
"sound": "default",
"channelId": "default"
}
}
}
}Parameters:
tokens(required): Array of FCM device tokensmessagesPerToken(optional): Number of messages to send per token (default: 10, max: 100)message(optional): Custom message object. If not provided, uses default template.
Success Response:
{
"success": true,
"summary": {
"totalTokens": 2,
"messagesPerToken": 10,
"totalMessages": 20,
"successCount": 20,
"failureCount": 0
},
"results": [
{
"token": "token1",
"messageIndex": 1,
"success": true,
"messageId": "0:1234567890",
"error": null
}
],
"sentAt": "2024-01-01T00:00:00.000Z"
}The message object in the request body supports all FCM message properties:
-
notification: The notification to show to the user
title: Notification titlebody: Notification body text
-
data: Custom key-value pairs (all values will be converted to strings)
- Use this to send custom data to your app
- Your app can handle this data even when in the background
-
android: Android-specific options
priority: Message priority ("high" or "normal")notification.sound: Notification soundnotification.channelId: Android notification channel ID
-
apns: iOS-specific options
- Configure iOS notification behavior
curl -X POST http://localhost:3000/push \
-H "Content-Type: application/json" \
-d '{
"tokens": ["your-fcm-device-token"],
"messagesPerToken": 5
}'fetch('http://localhost:3000/push', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
tokens: ['your-fcm-device-token'],
messagesPerToken: 5,
message: {
notification: {
title: 'Custom Title',
body: 'Custom message body'
},
data: {
eventId: '12345',
type: 'custom_event'
}
}
})
})
.then(res => res.json())
.then(data => console.log(data));- Make sure your
.envfile is properly configured - Verify that your Firebase Service Account JSON is valid
- Check that the file path (if using Method 1) is correct
- Verify that your FCM tokens are valid and not expired
- Make sure tokens are from the same Firebase project
- Check that your app is properly registered with FCM
- Ensure your server has internet connectivity
- Check if your firewall is blocking outgoing connections
- Verify that FCM services are not blocked
MIT
ν΄λ¦νμ¬ νκ΅μ΄ λ¬Έμ 보기
λΉ λ₯Έ μμ: ν μ€νΈλ₯Ό μν΄ νμν κ²μ Firebase μλΉμ€ κ³μ JSON νμΌκ³Ό FCM ν ν° λΏμ λλ€!
Expressλ₯Ό μ¬μ©ν Android/iOS κΈ°κΈ°λ‘ νΈμ μλ¦Όμ ν μ€νΈνκΈ° μν κ°λ¨ν μλ²μ λλ€.
- π νΈμ μλ¦Ό λ°μ‘μ μν κ°λ¨ν μΉ μΈν°νμ΄μ€
- π± λ€μ€ FCM ν ν° μ§μ
- π ν ν°λΉ μ¬λ¬ λ©μμ§ λ°μ‘ (λλ ν μ€νΈ)
- βοΈ μ»€μ€ν°λ§μ΄μ§ κ°λ₯ν λ©μμ§ JSON (notification, data, android/ios νΉμ μ€μ )
- π μ±κ³΅/μ€ν¨ κ°μκ° ν¬ν¨λ μμΈν μλ΅
- π― νΈμ μλ¦Ό ꡬν ν μ€νΈμ μλ²½ν¨
μ΄ μλ²λ₯Ό μ¬μ©νκΈ° μν΄ νμν κ²μ λ¨ λ κ°μ§μ λλ€:
- Firebase μλΉμ€ κ³μ JSON νμΌ - Firebase μ½μμμ λ°κΈλ°μΌμΈμ
- FCM λλ°μ΄μ€ ν ν° - λͺ¨λ°μΌ μ±μμ μ»μ μ μμ΅λλ€
μ΄κ²μ΄ μ λΆμ λλ€! 볡μ‘ν μ€μ μ΄ νμ μμ΅λλ€.
npm install- Firebase Consoleμ μ μ
- νλ‘μ νΈ μ ν
- νλ‘μ νΈ μ€μ > μλΉμ€ κ³μ νμΌλ‘ μ΄λ
- "μ λΉκ³΅κ° ν€ μμ±" ν΄λ¦νμ¬ JSON νμΌ λ€μ΄λ‘λ
- JSON νμΌμ μμ νκ² λ³΄κ΄
νλ‘μ νΈ λ£¨νΈμ .env νμΌμ μμ±νκ³ λ€μ λ°©λ² μ€ νλλ‘ Firebase μΈμ¦ μ 보λ₯Ό μ€μ νμΈμ:
λ°©λ² 1: JSON νμΌ κ²½λ‘ (λ‘컬 κ°λ°μ κΆμ₯)
FIREBASE_SERVICE_ACCOUNT_PATH=./path/to/your-firebase-service-account.jsonλ°©λ² 2: JSON μ 체λ₯Ό λ¬Έμμ΄λ‘ (λ°°ν¬μ μ ν©)
FIREBASE_SERVICE_ACCOUNT='{"type":"service_account","project_id":"your-project-id","private_key":"-----BEGIN PRIVATE KEY-----\n...","client_email":"firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com",...}'λ°©λ² 3: κ°λ³ νλ (νλ‘λμ μμ κ°μ₯ μμ )
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYour private key here\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project-id.iam.gserviceaccount.com# μΌλ° λͺ¨λ
npm start
# κ°λ° λͺ¨λ (nodemon μ¬μ©)
npm run devμλ²λ http://localhost:3000μμ μμλ©λλ€ (.env νμΌμ μ§μ λ PORT μ¬μ©).
- λΈλΌμ°μ μμ
http://localhost:3000μ μ - νλ μ΄μμ FCM λλ°μ΄μ€ ν ν° μ λ ₯
- (μ νμ¬ν) λ©μμ§ JSON 컀μ€ν°λ§μ΄μ§
- ν ν°λΉ λ°μ‘ν λ©μμ§ κ°μ μ€μ
- "λ°μ νκΈ°" λ²νΌ ν΄λ¦
1λ¨κ³: FCM ν ν° μ λ ₯
- FCM λλ°μ΄μ€ ν ν° μ λ ₯ (μ¬λ¬ ν ν° μ§μ)
- ν ν°λΉ λ°μ‘ν λ©μμ§ κ°μ μ€μ (κΈ°λ³Έκ°: 10)
- μ νμ μΌλ‘ "λ©μμ§ JSON 컀μ€ν°λ§μ΄μ§" μΉμ μ νΌμ³μ νΈμ μλ¦Όμ 컀μ€ν°λ§μ΄μ§ν μ μμ΅λλ€
2λ¨κ³: λ©μμ§ μ»€μ€ν°λ§μ΄μ§ (μ νμ¬ν)
- JSONμ νΈμ§νμ¬ μλ¦Ό μ λͺ©, λ³Έλ¬Έ, λ°μ΄ν° νλλ₯Ό 컀μ€ν°λ§μ΄μ§
- "ν¬λ§·ν " λ²νΌμ μ¬μ©νμ¬ JSON ν¬λ§· μ 리
- "κΈ°λ³Έκ°μΌλ‘ 리μ "μ μ¬μ©νμ¬ κΈ°λ³Έ ν νλ¦Ώ 볡μ
- "λ°μ΄ν° μμ λ‘λ"λ₯Ό μ¬μ©νμ¬ λ°μ΄ν°κ° νλΆν μμ νμΈ
- μ€λΉκ° λλ©΄ "λ°μ νκΈ°" ν΄λ¦
GET /health
μλ²μ FCMμ΄ μ λλ‘ μ΄κΈ°νλμλμ§ νμΈν©λλ€.
μλ΅:
{
"status": "ok",
"fcmInitialized": true,
"timestamp": "2024-01-01T00:00:00.000Z"
}GET /message-template
μλ²μμ μ¬μ©νλ κΈ°λ³Έ λ©μμ§ ν νλ¦Ώμ λ°νν©λλ€.
POST /push
Content-Type: application/json
μμ² λ³Έλ¬Έ:
{
"tokens": ["token1", "token2"],
"messagesPerToken": 10,
"message": {
"notification": {
"title": "ν
μ€νΈ μλ¦Ό",
"body": "ν
μ€νΈ λ©μμ§μ
λλ€"
},
"data": {
"key1": "value1",
"key2": "value2"
},
"android": {
"priority": "high",
"notification": {
"sound": "default",
"channelId": "default"
}
}
}
}λ§€κ°λ³μ:
tokens(νμ): FCM λλ°μ΄μ€ ν ν° λ°°μ΄messagesPerToken(μ ν): ν ν°λΉ λ°μ‘ν λ©μμ§ κ°μ (κΈ°λ³Έκ°: 10, μ΅λ: 100)message(μ ν): 컀μ€ν λ©μμ§ κ°μ²΄. μ 곡νμ§ μμΌλ©΄ κΈ°λ³Έ ν νλ¦Ώ μ¬μ©.
μ±κ³΅ μλ΅:
{
"success": true,
"summary": {
"totalTokens": 2,
"messagesPerToken": 10,
"totalMessages": 20,
"successCount": 20,
"failureCount": 0
},
"results": [
{
"token": "token1",
"messageIndex": 1,
"success": true,
"messageId": "0:1234567890",
"error": null
}
],
"sentAt": "2024-01-01T00:00:00.000Z"
}μμ² λ³Έλ¬Έμ message κ°μ²΄λ λͺ¨λ FCM λ©μμ§ μμ±μ μ§μν©λλ€:
-
notification: μ¬μ©μμκ² νμν μλ¦Ό
title: μλ¦Ό μ λͺ©body: μλ¦Ό λ³Έλ¬Έ ν μ€νΈ
-
data: 컀μ€ν ν€-κ° μ (λͺ¨λ κ°μ λ¬Έμμ΄λ‘ λ³νλ¨)
- μ±μ 컀μ€ν λ°μ΄ν°λ₯Ό μ μ‘νλ λ° μ¬μ©
- μ±μ΄ λ°±κ·ΈλΌμ΄λ μνμΌ λλ μ΄ λ°μ΄ν°λ₯Ό μ²λ¦¬ν μ μμ΅λλ€
-
android: Android νΉμ μ΅μ
priority: λ©μμ§ μ°μ μμ ("high" λλ "normal")notification.sound: μλ¦Ό μ¬μ΄λnotification.channelId: Android μλ¦Ό μ±λ ID
-
apns: iOS νΉμ μ΅μ
- iOS μλ¦Ό λμ ꡬμ±
curl -X POST http://localhost:3000/push \
-H "Content-Type: application/json" \
-d '{
"tokens": ["your-fcm-device-token"],
"messagesPerToken": 5
}'fetch('http://localhost:3000/push', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
tokens: ['your-fcm-device-token'],
messagesPerToken: 5,
message: {
notification: {
title: '컀μ€ν
μ λͺ©',
body: '컀μ€ν
λ©μμ§ λ³Έλ¬Έ'
},
data: {
eventId: '12345',
type: 'custom_event'
}
}
})
})
.then(res => res.json())
.then(data => console.log(data));.envνμΌμ΄ μ¬λ°λ₯΄κ² ꡬμ±λμλμ§ νμΈ- Firebase μλΉμ€ κ³μ JSONμ΄ μ ν¨νμ§ νμΈ
- νμΌ κ²½λ‘(λ°©λ² 1 μ¬μ© μ)κ° μ¬λ°λ₯Έμ§ νμΈ
- FCM ν ν°μ΄ μ ν¨νκ³ λ§λ£λμ§ μμλμ§ νμΈ
- ν ν°λ€μ΄ κ°μ Firebase νλ‘μ νΈμμ λ°κΈλμλμ§ νμΈ
- μ±μ΄ FCMμ μ λλ‘ λ±λ‘λμλμ§ νμΈ
- μλ²κ° μΈν°λ·μ μ°κ²°λμ΄ μλμ§ νμΈ
- λ°©νλ²½μ΄ μμλ°μ΄λ μ°κ²°μ μ°¨λ¨νμ§ μλμ§ νμΈ
- FCM μλΉμ€κ° μ°¨λ¨λμ§ μμλμ§ νμΈ
MIT

