A Node.js webhook server that receives data from The Things Network (TTN) and stores it in Firebase Firestore.
- Receives TTN webhook POST requests
- Extracts device data (battery, distance, tilt)
- Stores data in Firebase Firestore
- Supports both local development and production deployment
- Clone the repository
- Install dependencies:
npm install
- Place your
serviceAccountKey.jsonfile in the root directory - Start the server:
node index.js
- Test the webhook:
node test-webhook.js
Set the following environment variables in your Render service:
| Variable | Description | Example |
|---|---|---|
NODE_ENV |
Environment type | production |
FIREBASE_PROJECT_ID |
Firebase project ID | thethingsnetwork-16c4b |
FIREBASE_PRIVATE_KEY_ID |
Private key ID from service account | 6e97262b94f... |
FIREBASE_PRIVATE_KEY |
Private key from service account | -----BEGIN PRIVATE KEY-----\n... |
FIREBASE_CLIENT_EMAIL |
Client email from service account | firebase-adminsdk-...@...iam.gserviceaccount.com |
FIREBASE_CLIENT_ID |
Client ID from service account | 11234567890... |
FIREBASE_CLIENT_CERT_URL |
Client certificate URL | https://www.googleapis.com/robot/v1/metadata/x509/... |
FIREBASE_DATABASE_URL |
Firebase Realtime Database URL | https://your-project-default-rtdb.firebaseio.com/ |
- Push your code to GitHub
- Create a new Web Service on Render
- Connect your GitHub repository
- Set the build command:
npm install - Set the start command:
node index.js - Add all the environment variables listed above
- Deploy!
- Go to Firebase Console → Project Settings → Service Accounts
- Click "Generate New Private Key"
- Download the JSON file
- Extract the values and add them as environment variables:
type→ Not needed (hardcoded)project_id→FIREBASE_PROJECT_IDprivate_key_id→FIREBASE_PRIVATE_KEY_IDprivate_key→FIREBASE_PRIVATE_KEY(keep the newlines as\n)client_email→FIREBASE_CLIENT_EMAILclient_id→FIREBASE_CLIENT_IDclient_x509_cert_url→FIREBASE_CLIENT_CERT_URL
- POST
/ttn- Receives TTN webhook data
Expected payload structure:
{
"end_device_ids": {
"device_id": "your-device-id"
},
"received_at": "2023-01-01T00:00:00.000Z",
"uplink_message": {
"decoded_payload": {
"battery": 85,
"distance": 150.5,
"tilt": 12.3
}
}
}Data is stored in Firestore with the following structure:
iot-data/{deviceId}/messages/{auto-generated-id}
Each message document contains:
receivedAt: Timestamp when data was receivedbattery: Battery leveldistance: Distance measurementtilt: Tilt angle