Send Firebase WEB events from the SERVER using GA4 Measurement Protocol

By Ryan Romanchuk
On

The problem

The Analytics JS SDK (v9) is a wrapper and separate SDK from what Google is referring to as "The Google Tag" (gtag). The problem with the Firebase SDK is that it offers little to zero benefits, yet still requires cross site pixel drop, with no current support of GTM Server, ignoring transport_url or being able to load tags with your own endpoint, causing googletagmanager.com

Example server side Google Tag

<script async src="https://metrics.romanch.uk/gtag/js?id=G-24Q5EDRSF7" data-turbo-track="reload"></script>

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-24Q5EDRSF7', {
    'transport_url': 'https://metrics.romanch.uk'
  });
</script>

To use Measurement Protocol (Google Analytics 4) for Firebase, it requires both firebase_app_id and app_instance_id. The app_instance_id is generated on device and it's up to you to manage handing the token back to your S2S environment. In iOS this was trivial with Analytics.appInstanceID() in a standard REST environment. It has not been so obvious in the browser, but it is possible.

<script type="module">
    import { firebase } from "application";
    import { getInstallations, getId } from "firebase/installations";
    const installations = getInstallations(firebase)
    const installationId = await getId(installations);
    console.log(installationId);
    // You still have to get this back to the server, pass cookie, hidden input + stimulus post
    document.cookie = "iid=" + installationId + "; SameSite=Lax; Secure";
</script>

Full context

# config/importmap.rb
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"

pin "firebase/app", to: "https://www.gstatic.com/firebasejs/9.9.3/firebase-app.js"
pin "firebase/installations", to: "https://www.gstatic.com/firebasejs/9.9.3/firebase-installations.js"
// app/javascript/application.js
import "@hotwired/turbo-rails"
import "controllers"
import * as bootstrap from 'bootstrap';

fontAwesomeInit()
const firebase = firebaseInit()


export {  bootstrap, firebase };
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  private
  def iid() = cookies[:iid].presence
end
talk