Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add implementation of getGoogleAnalyticsClientId #7158

Merged
merged 24 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7071d2b
Add initial implementation of getGoogleAnalyticsClientId
dwyfrequency Mar 26, 2023
156137e
Update docs devsite
dwyfrequency Mar 26, 2023
510a89a
Add checkset
dwyfrequency Mar 26, 2023
41ef1bf
Update changeset description
dwyfrequency Mar 27, 2023
8f6ac07
Add link to client_id in docstring
dwyfrequency Mar 31, 2023
3e401cb
Update gtagWrapper to take variable number of args for potential fall…
dwyfrequency Apr 8, 2023
4c93e53
Add API test for getGoogleAnalyticsClientId
dwyfrequency Apr 10, 2023
c4b9792
Move API functionality to internal function
dwyfrequency Apr 11, 2023
54d83aa
Update docs for devsite
dwyfrequency Apr 11, 2023
2ecd32d
Removed unused function in test
dwyfrequency Apr 11, 2023
9f5cfb5
Update public api with async keyword
dwyfrequency Apr 11, 2023
c6d4109
Remove comment
dwyfrequency Apr 12, 2023
5516b49
Update doc string
dwyfrequency Apr 12, 2023
6eef67c
Update grammar of changeset
dwyfrequency Apr 12, 2023
eca9407
Remove console.log
dwyfrequency Apr 12, 2023
0e3b900
Update variable name from targetId to measurementId
dwyfrequency Apr 12, 2023
0ec1f27
Removed check for blank measurementId
dwyfrequency Apr 12, 2023
a585a16
Add ERROR_FACTORY for promise rejection
dwyfrequency Apr 13, 2023
953e499
Change fieldName from clientId
dwyfrequency Apr 13, 2023
7149472
Update AnalyticsError.NO_CLIENT_ID message
dwyfrequency Apr 13, 2023
93ed844
Merge branch 'master' into jd-getclientid-analytics-v2
dwyfrequency Apr 14, 2023
8332162
Testing adding comment
dwyfrequency Apr 18, 2023
888aba4
remove test comment
dwyfrequency Apr 18, 2023
9357f51
Remove comments
dwyfrequency Apr 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/silent-islands-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@firebase/analytics': minor
'firebase': minor
---

Add method `getGoogleAnalyticsClientId()` to retrieve an unique identifier for a web client. Users wanted to log purchase and other events from their backends using Google Analytics 4 Measurement Protocol and to have those events be connected to actions taken on the client within their Firebase web app. `getGoogleAnalyticsClientId()` will simply this event recording process.
3 changes: 3 additions & 0 deletions common/api-review/analytics.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ export interface EventParams {
// @public
export function getAnalytics(app?: FirebaseApp): Analytics;

// @public
export function getGoogleAnalyticsClientId(analyticsInstance: Analytics): Promise<string>;

// @public
export interface GtagConfigParams {
// (undocumented)
Expand Down
21 changes: 21 additions & 0 deletions docs-devsite/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Firebase Analytics
| [getAnalytics(app)](./analytics.md#getanalytics) | Returns an [Analytics](./analytics.analytics.md#analytics_interface) instance for the given app. |
| [initializeAnalytics(app, options)](./analytics.md#initializeanalytics) | Returns an [Analytics](./analytics.analytics.md#analytics_interface) instance for the given app. |
| <b>function(analyticsInstance...)</b> |
| [getGoogleAnalyticsClientId(analyticsInstance)](./analytics.md#getgoogleanalyticsclientid) | Retrieves a unique identifier for the web client. |
| [logEvent(analyticsInstance, eventName, eventParams, options)](./analytics.md#logevent) | Sends a Google Analytics event with given <code>eventParams</code>. This method automatically associates this logged event with this Firebase web app instance on this device.<!-- -->List of recommended event parameters can be found in [the GA4 reference documentation](https://developers.google.com/gtagjs/reference/ga4-events)<!-- -->. |
| [logEvent(analyticsInstance, eventName, eventParams, options)](./analytics.md#logevent) | Sends a Google Analytics event with given <code>eventParams</code>. This method automatically associates this logged event with this Firebase web app instance on this device.<!-- -->List of recommended event parameters can be found in [the GA4 reference documentation](https://developers.google.com/gtagjs/reference/ga4-events)<!-- -->. |
| [logEvent(analyticsInstance, eventName, eventParams, options)](./analytics.md#logevent) | Sends a Google Analytics event with given <code>eventParams</code>. This method automatically associates this logged event with this Firebase web app instance on this device.<!-- -->See [Track Screenviews](https://firebase.google.com/docs/analytics/screenviews)<!-- -->. |
Expand Down Expand Up @@ -121,6 +122,26 @@ export declare function initializeAnalytics(app: FirebaseApp, options?: Analytic

[Analytics](./analytics.analytics.md#analytics_interface)

## getGoogleAnalyticsClientId()

Retrieves a unique identifier for the web client.

<b>Signature:</b>

```typescript
export declare function getGoogleAnalyticsClientId(analyticsInstance: Analytics): Promise<string>;
```

### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| analyticsInstance | [Analytics](./analytics.analytics.md#analytics_interface) | |

<b>Returns:</b>

Promise&lt;string&gt;

## logEvent()

Sends a Google Analytics event with given `eventParams`<!-- -->. This method automatically associates this logged event with this Firebase web app instance on this device.
Expand Down
34 changes: 34 additions & 0 deletions packages/analytics/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,40 @@ export function setCurrentScreen(
).catch(e => logger.error(e));
}

/**
* Retrieves a unique identifier for the web client.
*
* @public
*
* @param app - The {@link @firebase/app#FirebaseApp} to use.
*/
export async function getGoogleAnalyticsClientId(
analyticsInstance: Analytics
): Promise<string> {
analyticsInstance = getModularInstance(analyticsInstance);
const measurementId = analyticsInstance.app.options.measurementId;
let clientId = '';
if (!measurementId) {
logger.error('The app has no recognizable measurement ID.');
} else {
clientId = await new Promise((resolve, reject) => {
wrappedGtagFunction(
GtagCommand.GET,
measurementId,
'client_id',
fieldName => {
if (!fieldName) {
reject('There was an issue retrieving the `client_id`');
}
resolve(fieldName);
}
);
});
}

return clientId;
}

/**
* Use gtag `config` command to set `user_id`.
*
Expand Down
3 changes: 2 additions & 1 deletion packages/analytics/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ export const enum GtagCommand {
EVENT = 'event',
SET = 'set',
CONFIG = 'config',
CONSENT = 'consent'
CONSENT = 'consent',
GET = 'get'
}
18 changes: 18 additions & 0 deletions packages/analytics/src/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,24 @@ describe('Gtag wrapping functions', () => {
expect((window['dataLayer'] as DataLayer).length).to.equal(1);
});

it('new window.gtag function does not wait when sending "get" calls', async () => {
wrapOrCreateGtag(
{ [fakeAppId]: Promise.resolve(fakeMeasurementId) },
fakeDynamicConfigPromises,
{},
'dataLayer',
'gtag'
);
window['dataLayer'] = [];
(window['gtag'] as Gtag)(
GtagCommand.GET,
fakeMeasurementId,
'client_id',
fieldName => console.log(fieldName)
);
expect((window['dataLayer'] as DataLayer).length).to.equal(1);
});

it('new window.gtag function waits for initialization promise when sending "config" calls', async () => {
const initPromise1 = new Deferred<string>();
wrapOrCreateGtag(
Expand Down
12 changes: 10 additions & 2 deletions packages/analytics/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,10 @@ function wrapGtag(
* @param gtagParams Params if event is EVENT/CONFIG.
*/
async function gtagWrapper(
command: 'config' | 'set' | 'event' | 'consent',
command: 'config' | 'set' | 'event' | 'consent' | 'get',
idOrNameOrParams: string | ControlParams,
gtagParams?: GtagConfigOrEventParams | ConsentSettings
gtagParams?: GtagConfigOrEventParams | ConsentSettings | string,
callback?: (s: string) => void
): Promise<void> {
try {
// If event, check that relevant initialization promises have completed.
Expand All @@ -255,6 +256,13 @@ function wrapGtag(
} else if (command === GtagCommand.CONSENT) {
// If CONFIG, second arg must be measurementId.
gtagCore(GtagCommand.CONSENT, 'update', gtagParams as ConsentSettings);
} else if (command === GtagCommand.GET) {
gtagCore(
GtagCommand.GET,
idOrNameOrParams as string,
gtagParams as string,
callback as (fieldName: string) => void
);
} else {
// If SET, second arg must be params.
gtagCore(GtagCommand.SET, idOrNameOrParams as CustomParams);
Expand Down
6 changes: 6 additions & 0 deletions packages/analytics/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ export interface Gtag {
subCommand: 'default' | 'update',
consentSettings: ConsentSettings
): void;
(
command: 'get',
targetId: string,
fieldName: string,
callback: (s: string) => void
): void;
}

export type DataLayer = IArguments[];