Closed twittergadungan closed 6 months ago
So app_instance_id
is a mobile-only concept tied to the idea of an installed app, which web does not have.
However, my understanding from digging through Measurement Protocol documentation is that there client_id
on web should serve the same purpose, but you have to send it to Measurement Protocol using the field client_id
instead of app_instance_id
.
Links (for my reference as well as yours): Measurement Protocol troubleshooting
Don't use advertising_id.
advertising_id is not supported as a valid device identifier. Use app_instance_id if you're using Firebase and client_id if you're using gtag.js."
This seems to indicate they both can serve the same purpose.
Given that, I suspect that part 2 of the gtag.js
tab on the Measurement Protocol "sending events" page is applicable, since the web SDK version of Firebase Analytics is actually a wrapper around gtag.js.
So we will think about providing a method in the web SDK that returns the client_id. In the meantime, as a workaround, you should be able to get it using gtag (which should be available globally in your environment if you've initialized Firebase Analytics for web):
From: https://developers.google.com/tag-platform/gtagjs/reference#get_mp_example
gtag('get', 'UA-XXXXXXXX-Y', 'client_id', (clientID) => {
sendOfflineEvent(clientID, "tutorial_begin")
});
function sendOfflineEvent(clientID, eventName, eventData) {
// Send necessary data to your server...
}
The "UA-XXXXXX-Y" arg is the measurement ID which you should be able to get from the Firebase console page for your project.
If you can try using that workaround and tell me if it works, that would be really helpful and would give us the green light to add the official method (probably called getClientId()
), which would basically be just that bit of code, wrapped in a promise and automatically supplying the measurementId.
So
app_instance_id
is a mobile-only concept tied to the idea of an installed app, which web does not have.However, my understanding from digging through Measurement Protocol documentation is that there
client_id
on web should serve the same purpose, but you have to send it to Measurement Protocol using the fieldclient_id
instead ofapp_instance_id
.Links (for my reference as well as yours): Measurement Protocol troubleshooting
Don't use advertising_id. advertising_id is not supported as a valid device identifier. Use app_instance_id if you're using Firebase and client_id if you're using gtag.js."
This seems to indicate they both can serve the same purpose.
Given that, I suspect that part 2 of the
gtag.js
tab on the Measurement Protocol "sending events" page is applicable, since the web SDK version of Firebase Analytics is actually a wrapper around gtag.js.So we will think about providing a method in the web SDK that returns the client_id. In the meantime, as a workaround, you should be able to get it using gtag (which should be available globally in your environment if you've initialized Firebase Analytics for web):
From: https://developers.google.com/tag-platform/gtagjs/reference#get_mp_example
gtag('get', 'UA-XXXXXXXX-Y', 'client_id', (clientID) => { sendOfflineEvent(clientID, "tutorial_begin") }); function sendOfflineEvent(clientID, eventName, eventData) { // Send necessary data to your server... }
The "UA-XXXXXX-Y" arg is the measurement ID which you should be able to get from the Firebase console page for your project.
If you can try using that workaround and tell me if it works, that would be really helpful and would give us the green light to add the official method (probably called
getClientId()
), which would basically be just that bit of code, wrapped in a promise and automatically supplying the measurementId.
@hsubox76
Hi Christina, thanks for the response. to test if a request is a valid GA4 Measurement protocol request we can use this Event Builder
please open this image: https://i.stack.imgur.com/4G7PL.png
as you can see, we can choose to use Firebase or gtag.js to send event to GA4 Measurement Protocol . in my case, I choose Firebase because I assume I can easily integrate the analytics to other Firebase products like remote config, FCM, in app messaging etc.
but unfortunately if I choose Firebase on that switch, then app_instance_id
field is required. so if I send clientID
to Measurement Protocol using the field client_id
instead of app_instance_id
then the Event Builder will see it as invalid event, because I have empty value on app_instance_id
as you can see from this documentation, app_instance_id
is required if I want to send it using Firebase, it can't be empty or null
I can send the request to Measurement Protocol using gtag.js (instead of Firebase) but I am worried I will lose all Firebase integration benefits for my Web App
I just want to double check, are you solely going off what the documentation/Event Builder says, or have you tried sending client_id instead of app_instance_id, and had it fail? I suspect the documentation may be incorrect, or at least misleading. I think the "firebase" switch might be for mobile Firebase SDKs only. As I mentioned above, the Firebase JS SDK actually uses gtag.js under the hood, so anything that works in gtag.js should theoretically work in the Firebase JS SDK. (Specifically the JS SDK only, the mobile SDKs do NOT use gtag.js.)
The fastest way to test it out would be to just send the client_id
with gtag as above in a live app. However if you're really unsure that gtag.js and the Firebase JS SDK will behave the same, you can also send the client_id
directly with the Firebase JS SDK.
logEvent(analytics, EVENT_NAME, { client_id: CLIENT_ID_HERE, /* any other params you are sending */ });
@hsubox76
we just used event builder. but unfortunately, we can't find that gtag
method so we can't get the clientID
. maybe because our front end developer is currently using Nuxt JS Firebase for Vue Web App
Can you clear up what you mean by "can't find that gtag method"? It's a global variable on window
that should become available any time after getAnalytics()
or initializeAnalytics()
is run, it's not a method you import.
Although looking at your link, that library you are using doesn't support modular v9 Firebase (I would really recommend migrating to something that does, when you are able to), so I guess the equivalent to getAnalytics()
in the compat version would be firebase.analytics()
. Unfortunately the library you linked has an odd setup, so I don't know when in its process that happens. Apparently it can be set to lazy mode where it doesn't initialize until manually called? https://firebase.nuxtjs.org/guide/options#lazy I don't know, I don't think we can provide support for that library, but whenever it finishes calling the equivalent of firebase.analytics()
is when you should be able to call the global gtag()
function.
We can try to create a test app ourselves to see if this works but it may take some time. So you can wait for that if you are not in a rush, or if you can test this out yourself and verify the approach works, we can fast-track creating the new getClientId()
method.
@hsubox76
Sorry. I think I made a fatal mistake, I forgot to change api_secret
and firebase_app_id
as URL Parameters . I used the Android api_secret
and firebase_app_id
instead of using api_secret
and firebase_app_id
for web app. so unfortunately I can confirm using client_id
as a replacement for app_instance_id
does not work
Ok, looks like we are going to have to do some testing and figure out what works on web, if anything. This may take some time, we will add updates in this issue when we discover anything new.
I was able to use the client_id from gtag with measurement protocol. @twittergadungan are you able to do the same? I am not sure the best way to see whether it is considered the same user in the Google Analytics dashboard but can see both events coming through. Note, it appears that MP events take much longer to propagate then do the events from gtag.
// gtag call
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
const measurementId = "INSERT-ID-HERE";
gtag("set", { currency: "USD" });
gtag("event", "purchase", {
client_id: "511285180.1674077316",
user_id: "USERID1",
timestamp_micros: "1674083595919000",
non_personalized_ads: false,
events: [
{
name: "purchase",
params: {
items: [
{ item_id: "ITEM_1", item_name: "coffee mugs", quantity: 1 },
],
affiliation: "GOOGLE STORE",
},
},
],
});
gtag("get", measurementId, "client_id", (clientID) => {
console.log({ clientID }); // gets you the client id for MP
});
// MP call
POST https://www.google-analytics.com/mp/collect?api_secret=<INSERT-SECRET-HERE>&measurement_id=<INSERT-ID-HERE>
HOST: www.google-analytics.com
Content-Type: application/json
{"client_id":"<ID-FROM-GTAG-GET>","user_id":"USERID1","timestamp_micros":"1674152143864000","non_personalized_ads":false,"events":[{"name":"refund","params":{"items":[{"item_id":"ITEM_1","item_name":"coffee mugs","quantity":1}],"affiliation":"GOOGLE STORE"}}]}
@hsubox76
It's a global variable on window that should become available any time after getAnalytics() or initializeAnalytics() is run
gtag('get', 'UA-XXXXXXXX-Y', 'client_id', (clientID) => { log.info(clientID) });
I tried the above steps and was able to get the gtag instance too, however the get
method never returns anything. The callback is never called.
Logging the window.gtag function to console, I get this:
async function gtagWrapper(command, idOrNameOrParams, gtagParams) {
try {
// If event, check that relevant initialization promises have completed.
if (command === "event" /* GtagCommand.EVENT */) {
// If EVENT, second arg must be measurementId.
await gtagOnEvent(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, idOrNameOrParams, gtagParams);
} else if (command === "config" /* GtagCommand.CONFIG */) {
// If CONFIG, second arg must be measurementId.
await gtagOnConfig(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, idOrNameOrParams, gtagParams);
} else if (command === "consent" /* GtagCommand.CONSENT */) {
// If CONFIG, second arg must be measurementId.
gtagCore("consent" /* GtagCommand.CONSENT */, 'update', gtagParams);
} else {
// If SET, second arg must be params.
gtagCore("set" /* GtagCommand.SET */, idOrNameOrParams);
}
} catch (e) {
logger.error(e);
}
}
Not sure the Firebase gtagWrapper
implements the get method. Or am I missing something here?
@abhi-gn we need to update the firebase gtag wrapper implementation to account for get
calls. The wrapper is limited and doesn't take into account commands other than event, config, consent, and set https://github.com/firebase/firebase-js-sdk/blob/3ee35f9ae575018fa7617bd3ac69b99fbb5cc8e6/packages/analytics/src/helpers.ts#L260. For now, use the example https://github.com/firebase/firebase-js-sdk/issues/6881#issuecomment-1400895044 in a basic html project with no firebase installed.
Using a basic project with gtag, are you able to see if client_id will suffice? Also, would you mind sharing a screenshot or other resource of how you plan to track this in Google Analytics
@dwyfrequency Thanks for clearing this up. We are already in the process of setting up Firebase analytics for our React web project and using Firebase JS SDK for that.
Now we want to track the tab close event with some collated data as attributes and were looking for ways to achieve that. One obvious way is to call an api using the browser's sendBeacon
method. Which is where we are trying to call the /mp/collect
api, kind of like your example but instead of a GA tag we have Firebase JS sdk.
It is still unclear to me whether Firebase sdk automatically handles sending of events using sendBeacon
in cases like tab close etc. (Would be great if it does :) )
@abhi-gn would you mind raising a separate issue for this question and link it? The latest inquiry deviates from the original question raised by @twittergadungan.
I was able to use the client_id from gtag with measurement protocol. @twittergadungan are you able to do the same? I am not sure the best way to see whether it is considered the same user in the Google Analytics dashboard but can see both events coming through. Note, it appears that MP events take much longer to propagate then do the events from gtag.
// gtag call window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag("js", new Date()); const measurementId = "INSERT-ID-HERE"; gtag("set", { currency: "USD" }); gtag("event", "purchase", { client_id: "511285180.1674077316", user_id: "USERID1", timestamp_micros: "1674083595919000", non_personalized_ads: false, events: [ { name: "purchase", params: { items: [ { item_id: "ITEM_1", item_name: "coffee mugs", quantity: 1 }, ], affiliation: "GOOGLE STORE", }, }, ], }); gtag("get", measurementId, "client_id", (clientID) => { console.log({ clientID }); // gets you the client id for MP });
// MP call POST https://www.google-analytics.com/mp/collect?api_secret=<INSERT-SECRET-HERE>&measurement_id=<INSERT-ID-HERE> HOST: www.google-analytics.com Content-Type: application/json {"client_id":"<ID-FROM-GTAG-GET>","user_id":"USERID1","timestamp_micros":"1674152143864000","non_personalized_ads":false,"events":[{"name":"refund","params":{"items":[{"item_id":"ITEM_1","item_name":"coffee mugs","quantity":1}],"affiliation":"GOOGLE STORE"}}]}
@twittergadungan you mentioned so unfortunately I can confirm using client_id as a replacement for app_instance_id does not work.
Can you show a screenshot of how you verified this does not work in Google Analytics? We were able to call the MP endpoint in my linked example with client_id and we would like to see how you determined it was an unsuitable.
@dwyfrequency
hi Sorry for late response. here is what I did:
function gtag(){
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'code-gtag-configxxxxxx');
gtag('get', 'code-gtag-configxxxxxx', 'client_id', (client_id) => {
gtag_client_id= client_id
console.log("client id: ", client_id)
})
purchase
event which is a conversion event.as you can see, I use web firebase_app_id
in the query parameter, the id is something like this 1:1******26811:web:4b*******bc7e13ae5f9e
. and I got 204 status code that indicates that the request had succeeded.
as you can see, the purchase event is not recorded in Firebase console
firebase_app_id
from web ( 1:1******26811:web:4b*******bc7e13ae5f9e
) to Android firebase app id (1:121******811:android:674*******da4fae5f9e
), I can see the purchase event is recorded on my Firebase console@twittergadungan can you check again in 24 hours? Previously, I noticed , it appears that MP events take much longer to propagate then do the events from gtag. Gtag events were almost immediate but I usually saw Measurement Protocol events in GA the next day.
@dwyfrequency
Unfortunately after 3 days, I still can't see the purchase events on GA4 dashboard.
Works for me, thanks. @twittergadungan try sending measurementId
instead of firebase_app_id
@goodspeed3
so I just need to rename the firebase_app_id
to be measurementId
in the query parameters but the value is still the same?
@twittergadungan yes, it should be measurement_id
.
In the event builder, you can see it mentions using gtag for web apps which is what the firebase js sdk uses under the hood. First, choose the client you are using with the toggle below. Mobile implementations should use firebase, and web implementations should use gtag.js
One thing to note is that the events from Measurement Protocol seem to take a long time to propagate into the GA dashboard. I'm going to keep investigating why this is the case, possibly my own settings. For example, I sent this from postman yesterday and it did eventually appear but it took a long time.
curl --location --request POST 'https://www.google-analytics.com/mp/collect?api_secret=SECRET&measurement_id=MEASUREMENT_ID' \
--header 'Content-Type: text/plain' \
--data-raw '{"client_id":"511285180.1674077316","user_id":"USERID1","timestamp_micros":"1677512966734000","non_personalized_ads":false,"events":[{"name":"purchase","params":{"items":[{"item_id":"ITEM_1","item_name":"coffee mugs","quantity":1}],"affiliation":"GOOGLE STORE"}}]}'
@dwyfrequency
Thank you very much for the response, I really appreciate it. I will try and I will update the result
but to be honest I am worried if I create using gtag in the backend, the data will not appear and will not integrate into my Firebase console. I need to use Firebase because I assume I can easily integrate the analytics to other Firebase products like Firebase Remote config, Firebase A/B Testing, Firebase Cloud Messaging etc. so I can track user behaviour in all devices. Android, iOS and Web App
Thats why I create a feature request so I can use Measurement Protocol on my Firebase Web App
@dwyfrequency
I can see the purchase event data when creating data via gtag, and I can immediately see the data on my Firebase Realtime Analytics , and you are right it needs time to appear on GA dashboard.
@twittergadungan happy to see that's working for you. Would having an explicit method in the analytics package like getClientId()
be helpful to your use case? If so, I'll submit an internal proposal to.
@twittergadungan happy to see that's working for you. Would having an explicit method in the analytics package like
getClientId()
be helpful to your use case? If so, I'll submit an internal proposal to.
yes, I think it will be great and simplify the process to get the client ID without using gtag and measurement ID
lol i was literally fishing it out of the cookies for S2S, so smelly.
# Cookie where client_id is stored
# _ga=GA1.3.xxxxxxx.xxxxxxxx
def ga
@ga ||= cookies[:_ga].presence
end
# "GS1.1.xxxxx.70.1.xxxxxxx.60.0.0"
# _ga_MEASUREMENTID
def ga_session
@ga_session ||= cookies[Rails.configuration.general.firebase_session_cookie].presence
end
def cid
@cid ||= ga&.split(".")&.last(2)&.join(".")
end
def sid
@sid ||= ga_session&.split(".")&.[](2)
end
Oops, forgot to update this issue but this method was added in April 2023: https://firebase.google.com/support/release-notes/js#version_9210_-_april_27_2023
[REQUIRED] Describe your environment
[REQUIRED] Describe the problem
Steps to reproduce:
I am trying to log
purchase
event from my backend using Google Analytics 4 Measurement Protocol, if read this documentation, it is said that I must haveapp_instance_id
so I can send the data from our backend to Google Analytics 4 server.as you can read from that documentation, the
app_instance_id
is a unique identifier for a Firebase app instance. but the problem is I can't get thatapp_instance_id
for my Web App instance ( I can get it easily for my Firebase Android and iOS app in Firebase Analytics module)please provide the API to get the
app_instance_id
for Firebase Web App. it is very important, because if I can logpurchase
event or other events from my backend, I can associate that event to certain user so I can easily make custom audience (Purchaser) that can be exported to Google Ads so I can spend my money more effectively on Google Ads