How to add Firebase analytics in the DroidScript app

68 views
Skip to first unread message

DogPlanner GSS

unread,
Apr 7, 2026, 6:04:43 AM (8 days ago) Apr 7
to DroidScript
Dear Developers,

we want to add possipbilty of Firebase analytics to the our app. Is it possible at all?
If yes, could you tell us pls what we need to insert in our DroidScript code for this task?

Thank you very much in advance.

Best regards
Dmitry

Dave

unread,
Apr 8, 2026, 2:30:22 PM (7 days ago) Apr 8
to DroidScript
Hi Dmitry,

Are you using an HTML app or a WebView or a Hybrid app?

DogPlanner GSS

unread,
Apr 9, 2026, 4:58:11 AM (6 days ago) Apr 9
to DroidScript
Dear Dave,

we are making the native app (it is waterpas, compas, luxmeter with funny background). We placed the app at the AppGallery and local store. And now it will be useful for us to know has anyone downloaded it at all?))

Here it is:

Can you recommend something in this case for analytics?

Thank you very much in advance.

Have a nice day.

Best regrads
Dmitry
среда, 8 апреля 2026 г. в 21:30:22 UTC+3, Dave:

Dave

unread,
Apr 12, 2026, 11:57:03 AM (3 days ago) Apr 12
to DroidScript
If you are using a WebView (which DroidScript does internally), then you need to talk directly to the back-end of GA (measurements API) because the normal GA functions expect a standard browser.

You don't need to setup Firebase Analytics or use Tag-Manager, just setup a basic GA4 account and WebStream Property and use the following code (or similar).  Ignore all the stuff about gtag.js in the GA docs.

You will be able to see the live data arriving in the GA 'Realtime Overview', but the map 'dot' will not move from the coast of Africa in that realtime view, however the data is still being accumulated and you can see the results properly in correct place on the map in the main reports area after about 24h, along with the rest of the data.

You should setup some 'Custom Definitions/Custom Dimensions' for any of your custom event data fields that you want to filter through to the main reporting screens and make available for generating dashboards etc.

If you want decent reports and nice graphs, I highly recommend using 'Looker Studio' as this can connect directly to GA and produce nice customisable dashboards with shareable charts.

/*
        ga-direct.mjs
  
This code sends data direct to the GA measurements end-points
to avoid errors when running ga.js locally or with no DOM.

  Trigger a custom GA event.
  (you can add any fields you like to this)
 
  import { sendCustomEvent } from "./ga-direct.mjs"
 
    sendCustomEvent( app.GetDeviceId(), buttonName+'_touch', {
      buttonName: buttonName,
      screenName: screenName,
      page_context: 'home'
    })

*/


//Google Analytics config.
const DEBUG = false
const MEASUREMENT_ID = 'G-NXXXXXXJHW'
const API_SECRET = 'T-E-OFkXXXX_nzW8dp-Dg'
const CITY = 'Paris'


export function sendCustomEvent(clientId, name, params) {
    sendEvent(clientId, name, {
        session_id: getSessionId(),
        session_engaged: 1,
        engagement_time_msec: 100,
        ...params
    });
}

export function sendPageView(clientId, title, virtualUrl) {
    sendEvent(clientId, 'page_view', {
        page_title: title,
        page_location: virtualUrl,
        page_referrer: document.referrer || 'none',
        session_id: getSessionId(),
        session_engaged: 1,
        engagement_time_msec: 100
    });
}

async function sendEvent(clientId, name, params = {}) {
    const cleanedParams = {};

// Clean up values to keep GA happy.
    for (const [key, value] of Object.entries(params)) {
        const cleanKey = clean(key)
        let cleanValue
        if (typeof value === 'string') cleanValue = clean(value)
        else cleanValue = value
        if (cleanKey) cleanedParams[cleanKey] = cleanValue
    }

    const endpoint = `https://www.google-analytics.com/mp/collect?` +
        `measurement_id=${encodeURIComponent(MEASUREMENT_ID)}` +
        `&api_secret=${encodeURIComponent(API_SECRET)}`;

    const body = {
        client_id: toStableGaClientId(clientId),
        //user_location: { city: "Leeds", region_id: "GB-LDS", country_id: "GB" },
        user_location: { city: CITY, region_id: 'GB-ENG', country_id: 'GB' },
        //ip_override: '81.143.128.0',
        events: [{ name, params: cleanedParams }]
    };

    try {
        const res = await fetch(endpoint, {
            method: 'POST',
            headers: { 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0' },
            body: JSON.stringify(body)
        })
        if (!res.ok) console.error('GA4 MP error:', res.status, await res.text());
        else if( DEBUG ) console.log('GA4 MP event sent:', name, JSON.stringify(body,0,2) )
    } catch (e) {
        console.error('GA4 MP fetch failed:', e)
    }
}

function toStableGaClientId(input) {
  const s = String(input ?? '').trim()

  // If it's already GA-ish, keep it
  if (/^\d+\.\d+$/.test(s)) return s

  // FNV-1a 64-bit hash (BigInt) - deterministic and fast
  let h = 0xcbf29ce484222325n
  for (let i = 0; i < s.length; i++) {
    h ^= BigInt(s.charCodeAt(i))
    h = (h * 0x100000001b3n) & 0xffffffffffffffffn
  }

  // Client "random" portion (keep it reasonably sized)
  const clientPart = Number(h % 10000000000n) // 0..9,999,999,999

  // Deterministic "timestamp" portion, but keep it plausible
  // Map into 2019-01-01 .. 2030-01-01
  const base = 1546300800n // 2019-01-01T00:00:00Z
  const span = 347129280n  // 11 years in seconds (approx; good enough)
  const tsPart = Number(base + ((h >> 32n) % span))

  return `${clientPart}.${tsPart}`
}


function getSessionId() {
  if( !window._sid )
    window._sid = Math.floor(Date.now()/1000)

  return window._sid
}

function newSession() {
    window._sid = Date.now().toString()
}

function activateUser() {
    sendEvent('user_engagement', {
      session_id: getSessionId(),
      engagement_time_msec: 5000,
      session_engaged: 1
    })
}

function clean(s) {
  if (!s) return '';

  return s
    .toLowerCase()
    .replace(/[^a-z0-9]/g, '_')
    .substring(0, 40);
}





DogPlanner GSS

unread,
Apr 13, 2026, 12:22:53 PM (2 days ago) Apr 13
to DroidScript
Dear Dave,

thank you very much that you found the time and gave detailed answer! We will learn all of these instruments and your code for using in our apps. We really like DroidScript and hope it will be developed in the future.

Thank you very much once again. Have a nice day and week.

Best regards
Dmitry

воскресенье, 12 апреля 2026 г. в 18:57:03 UTC+3, Dave:
Reply all
Reply to author
Forward
0 new messages