Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion apps/sim/lib/consent/google-context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GOOGLE_CLICK_ID_PARAMETERS, UTM_PARAMETERS } from '@/lib/analytics/campaign-parameters'
import { isNoindexPath } from '@/lib/navigation/paths'
import { isNoindexPath, isPathOrDescendant } from '@/lib/navigation/paths'

const GOOGLE_ANALYTICS_ORIGINS = new Set(['https://sim.ai', 'https://www.sim.ai'])

Expand Down Expand Up @@ -51,6 +51,7 @@ export function getGooglePageLocation(value: string): string | undefined {
try {
const url = new URL(value)
if (!GOOGLE_ANALYTICS_ORIGINS.has(url.origin)) return undefined
if (isPathOrDescendant(decodeURIComponent(url.pathname), '/extension')) return undefined
Comment thread
waleedlatif1 marked this conversation as resolved.
Resolved

const campaign = new URLSearchParams()
for (const parameter of GOOGLE_CAMPAIGN_PARAMETERS) {
Expand Down
49 changes: 48 additions & 1 deletion apps/sim/lib/consent/scripts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
trackGoogleEvent,
trackGooglePageView,
} from '@/lib/analytics/google'
import { getGooglePageLocation } from '@/lib/consent/google-context'
import { getGooglePageLocation, updateGooglePageContext } from '@/lib/consent/google-context'
import {
type ConsentScriptCallbackInfo,
GOOGLE_ADS_ID,
Expand Down Expand Up @@ -101,6 +101,53 @@ describe('consent scripts', () => {
expect(getGooglePageLocation('https://www.sim.ai/library')).toBeUndefined()
})

it.each(['/extension', '/extension/o/org-id', '/%65xtension/workspace-id'])(
'does not register third-party tracking scripts for %s',
(path) => {
window.history.replaceState({}, '', path)

expect(getGlobalConsentScripts()).toEqual([])
expect(getGooglePageLocation(window.location.href)).toBeUndefined()
}
)

it('stops Google events when navigating into the extension and resumes on public pages', () => {
window.history.replaceState({}, '', '/library')
getGlobalConsentScripts()[0]?.onBeforeLoad?.(CALLBACK_INFO)
window.dataLayer = []
window.history.pushState({}, '', '/extension/o/private-org?utm_source=google')

trackGooglePageView('/extension/o/private-org')
trackGoogleEvent('sign_up', { method: 'email' })
trackGoogleAdsConversion('demo_booked')

expect(window.dataLayer).toEqual([])

window.history.pushState({}, '', '/extension-guide')
trackGooglePageView('/extension-guide')
expect(window.dataLayer).toContainEqual([
'event',
'page_view',
{
page_path: '/extension-guide',
page_location: 'https://www.sim.ai/extension-guide',
send_to: GOOGLE_ANALYTICS_ID,
},
])
})

it('removes extension scope IDs from referrals to public pages', () => {
window.history.replaceState({}, '', '/library')
getGlobalConsentScripts()[0]?.onBeforeLoad?.(CALLBACK_INFO)

updateGooglePageContext(window.location.href, 'https://www.sim.ai/extension/o/private-org')

expect(window.dataLayer.at(-1)).toEqual([
'set',
expect.objectContaining({ page_referrer: 'https://www.sim.ai/extension' }),
])
})

it('keeps supported campaign parameters and removes unknown parameters and fragments', () => {
expect(
getGooglePageLocation(
Expand Down
10 changes: 9 additions & 1 deletion apps/sim/lib/consent/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { gtag } from '@c15t/scripts/google-tag'
import { xPixel } from '@c15t/scripts/x-pixel'
import { FREEBUFF_TAG_SRC, installFreebuffStub } from '@/lib/analytics/freebuff'
import { getGooglePageLocation, updateGooglePageContext } from '@/lib/consent/google-context'
import { isPathOrDescendant } from '@/lib/navigation/paths'

export const GOOGLE_ANALYTICS_ID = 'G-QB9D67TBHR' as const

Expand Down Expand Up @@ -67,8 +68,15 @@ const GLOBAL_CONSENT_SCRIPTS = [
},
] as const

/** Registers Google's shared destination only on Sim's actual production origins. */
/** Excludes embedded extension pages and restricts Google's loader to production origins. */
export function getGlobalConsentScripts() {
if (typeof window !== 'undefined') {
try {
if (isPathOrDescendant(decodeURIComponent(window.location.pathname), '/extension')) return []
} catch {
return []
}
}
const googleEnabled =
typeof window !== 'undefined' && getGooglePageLocation(window.location.href) !== undefined
return GLOBAL_CONSENT_SCRIPTS.filter((script) => script.id !== 'gtag' || googleEnabled)
Expand Down
1 change: 1 addition & 0 deletions apps/sim/lib/navigation/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function isAppSurfacePath(pathname: string): boolean {
*/
const NOINDEX_PATH_ROOTS = [
'/chat',
'/extension',
'/resume',
'/invite',
'/unsubscribe',
Expand Down
Loading