Firebase Costs Increased by 7,000%!
...I used only a few MB of bandwidth — yet their analytics showed 2 GB for that same period!
...they informed me that their profiling tool does not show this SSL overhead
Firebase has finished providing the credits and we have a meeting scheduled next week to dig deeper into usage. They have been great since I got in contact with Alex & Andrew over there. They have definitely resolved this issue in my eyes and I feel they have a better handle on how to handle this moving forward so this doesn’t happen to others!
We told them that we spent the full 25k grant we had just a few days ago and see the chance to apply for the 100k grant on Google Cloud Services. We contacted the team of Google Developers Latam, to tell them what had just happened. They allowed us to apply for the next grant, which google approved,
How we spent 30k USD in Firebase in less than 72 hours
We had reached more than 2 million sessions, more than 20 million pages visited...
We did more than 46 BILLION requests to Firestore
... It was just one bad line of code that was causing that amount of requests
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
Notification.requestPermission(status => {
console.log('Notification permission status:', status, true);
});
Request Permissions
Possible values:
Notification.permission
You need permissions to send
You need a service worker to display notifications
navigator.serviceWorker.register('serviceworker.js', {scope: '/'})
.then(function(reg) {
log('Registration succeeded. Scope is ' + reg.scope);
}).catch(function(error) {
log('Registration failed with ' + error);
});
// serviceworker.js
console.log('service worker here');
payload = {
notification : {
"title": "Push notification",
"body": "No payload so default value here",
"badge": "/logo.png"
}
} },
navigator.serviceWorker.getRegistration().then(function(reg) {
var time = Date.now() - 60*10;
var options = {
body: payload.notification.body,
icon: payload.notification.badge,
"webpush": {
"headers": {
"Urgency": "high"
},
"notification": {
"title": "Web title",
"body": "Web body",
"badge": "/logo.png"
},
}
};
reg.showNotification(payload.notification.title, options);
});
var messaging = firebase.messaging();
function getToken(){
messaging.getToken().then(function(currentToken) {
if (currentToken) {
console.log("We have a token: " + currentToken);
sendTokenToServer(currentToken);
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
}).catch(function(err) {
console.log('An error occurred while retrieving token. ', err);
});
}
// Callback fired if Instance ID token is updated.
messaging.onTokenRefresh(function() {
messaging.getToken().then(function(refreshedToken) {
console.log('Token refreshed.');
console.log("We have a token: " + refreshedToken);
sendTokenToServer(refreshedToken);
}).catch(function(err) {
console.log('Unable to retrieve refreshed token ', err);
});
});
Get the token. Save it on your server
// When web page in foreground in main web page when app is in the foreground
messaging.onMessage(function(payload) {
console.log('Message received. ', payload);
displayNotification(payload);
});
// in service worker firebase-messaging-sw.js
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
var notificationTitle = 'Background Message Title';
var notificationOptions = {
body: 'Background Message body.',
icon: '/firebase-logo.png'
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
Depends if app is in the foreground or background
const {google} = require('googleapis');
const SCOPES = "https://www.googleapis.com/auth/firebase.messaging";
const SERVICE_ACCOUNT_JSON_FILE = 'SERVICE_ACCOUNT.json'
function getAccessToken() {
return new Promise(function(resolve, reject) {
var key = require(SERVICE_ACCOUNT_JSON_FILE);
var jwtClient = new google.auth.JWT(
key.client_email,null,key.private_key,SCOPES, null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
getAccessToken().then(function(err, tokens){
if (err) {
console.error(err);
return;
}
console.log(tokens);
});
{
"message": {
"token" : "fByerczVlXk:APA91bGKIcOPQOq6ImL....",
"notification": {
"title": "Default Title",
"body": "Default Content"
},
"webpush": {
"headers": {
"Urgency": "high"
},
"notification": {
"title": "Web push title",
"body": "Web push body",
"badge": "/logo.png",
"click_action": "https://google.com"
},
"fcm_options": {
"link": "https://yahoo.com"
}
}
}
}
POST to https://fcm.googleapis.com/v1/projects/{{ProjectName}}/messages:send
Headers
Content-Type: application/json
Authorization: Bearer {{AccessToken}}
POST to https://iid.googleapis.com/iid/v1/{{TOKEN}}/rel/topics/{{TOPIC_NAME}}
Headers
Content-Type: application/json
Authorization: key={{ SERVER_KEY }}
{
"message": {
"topic": "topic_name1",
"notification": {
"title": "Topic 1",
"body": "Message by topic"
},
"webpush": {
"notification": {
"click_action": "https://yahoo.com"
},
"fcm_options": {
"link": "https://dummypage.com"
}
}
}
}
POST to https://fcm.googleapis.com/v1/projects/{{ProjectName}}/messages:send
Headers
Content-Type: application/json
Authorization: Bearer {{AccessToken}}
{
"message": {
"topic": "topic_name1",
"notification": {
"title": "Topic 1",
"body": "Message by topic"
}
}
}
POST to https://fcm.googleapis.com/fcm/send
Headers
Content-Type: application/json
Authorization: key= {{ SERVER_KEY }}
DELETE to https://iid.googleapis.com/v1/web/iid/{{TOKEN}}
Headers
Content-Type: application/json
Authorization: key= {{ SERVER_KEY }}
usePublicVapidKey