โ‡ Back to Blog

Your Portal Sees the Click Into a Licensed Game. After That, the Browser Stops Telling You Anything.

Published on

When you license HTML5 games and embed them, your analytics stops at the iframe border. The browser enforces that, and most licence agreements never mention it.

The conversation always starts with a ranked list. Somebody exports the top fifty game pages by views, prints it, and the meeting proceeds as though that list ranks the games. It does not. It ranks your thumbnails, your category placement, your internal linking and whatever the homepage carousel happened to be showing. Every number on that page was generated before a single frame of the game rendered.

This is the quiet structural problem in running a portal on licensed content. You are accountable for retention, for which titles stay and which get culled, for whether the catalogue is earning its licence fee โ€” and the one place where all of that actually happens is a document you cannot read.

๐Ÿšง The Frame Border Is a Security Boundary, Not a Missing Feature

A licensed title running in an iframe on your portal is a second document, from a different origin, sitting inside your page. The same-origin policy governs what your page may do with it, and the answer is: almost nothing. Mozilla's same-origin policy reference puts it plainly โ€” APIs such as iframe.contentWindow and window.parent "allow documents to directly reference each other", but when the two documents are cross-origin those references "provide very limited access to Window and Location objects".

Very limited means a short list. You may call postMessage, focus, blur and close on the other window, and read a handful of properties such as frames, length, closed and parent. That is the whole surface. The DOM inside the frame, the canvas, the game's own variables, its network calls, its error console โ€” all closed. Storage is closed too: the same reference states that Web Storage and IndexedDB "are separated by origin. Each origin gets its own separate storage, and JavaScript in one origin cannot read from or write to the storage belonging to another origin."

Nothing in your tag manager fixes this, and any vendor pitching "iframe tracking" is selling one of exactly two things โ€” postMessage plumbing that requires the game to cooperate, or a same-origin setup where you host the build yourself. Both are licence questions before they are engineering questions.

๐Ÿ“Š The Three Numbers That Survive the Boundary

Before writing off the frame entirely, be precise about what you do still get, because operators routinely undervalue the third one.

The click-in. Entirely yours, entirely reliable, and entirely a measure of your merchandising rather than the game. Treat it as a traffic number and never as a quality number.

Frame load completion. The load event on the iframe element fires in your page even when the framed document is cross-origin. It tells you the document finished loading. It does not tell you the game booted โ€” a build that throws during initialisation and shows a black rectangle forever fires load exactly like a healthy one.

Engagement time. Google Analytics 4 defines user engagement as the time a page spends in focus in the foreground, recorded in milliseconds and sent as an engagement_time_msec parameter when the user backgrounds the tab, navigates away or closes it. The game lives inside your page, so that clock keeps running while somebody plays. This is the single most useful number you get for free, and it is blunt in one specific way: it cannot distinguish a focused tab being played from a focused tab being ignored, and it cannot attribute a second of it to anything that happened in the game.

Here is what you never get without cooperation: whether the player took a first input at all, level completions, retries, session depth, the drop-off point, in-game ad requests and fill, mute rate, crash-on-boot rate, and first-input latency on low-end hardware. The asymmetry is worth saying out loud. If the build carries the licensor's SDK and phones home, the licensor sees most of that list. You see the doorway.

๐Ÿ”Œ postMessage Works โ€” But Only If the Build Speaks First

The sanctioned channel across the boundary is window.postMessage, and wiring up a listener on the parent side is roughly ten lines of code. You can ship it this afternoon. The catch is that a listener hears nothing unless the framed build chooses to speak, and a large share of licensed catalogue builds โ€” particularly older ones ported from a different distribution context โ€” post nothing at all.

If you do add the listener, treat it as untrusted input from day one. Bound the receiver with an explicit targetOrigin, validate incoming messages against an exact event.origin match rather than a substring check, verify event.source is the frame you expect, and schema-validate the payload. A listener that acts on any message it receives is a script-injection path into your own portal, opened by your analytics team.

There is a useful diagnostic in that listener even before anyone cooperates: log every message you receive from game frames, including the ones you do not recognise. Within a week you will know which titles in your catalogue already emit something, which usually maps cleanly onto build vintage.

๐Ÿงพ Ask for the Event Vocabulary by Name

"Can we get analytics on the games?" is a question that generates a meeting. Naming the events generates an answer, and the industry has already converged on a vocabulary you can borrow from published platform documentation.

Poki's SDK documentation defines gameLoadingFinished, gameplayStart, gameplayStop, commercialBreak and rewardedBreak, and specifies the sequencing โ€” a death-and-restart, for example, is documented as gameplayStop, then commercialBreak, then gameplayStart. CrazyGames' HTML5 v2 SDK defines sdkGameLoadingStart and sdkGameLoadingStop for the loading phase, the same gameplayStart and gameplayStop pair for active play, and a happytime call for achievement moments. Different platforms, near-identical event model.

That model is your specification. Five events โ€” loading finished, gameplay start, gameplay stop, ad opportunity, rewarded ad completed โ€” are enough to compute conversion from page view to first input, real play time as distinct from focused idle time, session depth, and ad opportunities per session. That is most of what you thought your dashboard was already telling you.

So put three questions to the licensor instead of one. Which analytics or ad SDK, if any, is compiled into the builds you are licensing, and where does it report to? Does the licence permit you to modify the build to add a postMessage bridge or your own instrumentation? And will the licensor supply a variant that posts those events to the parent frame? The third is often the cheapest of the three to deliver โ€” a wrapper around existing calls rather than a rebuild โ€” and it is a reasonable ask at catalogue scale. Ask before signature. After signature it becomes a change request with a quote attached.

Expect the answer to vary across a large catalogue. A thousand titles is many build vintages and several engines. Ask for the split, not the headline.

๐Ÿ’พ Storage Partitioning Made the Save File Yours โ€” On Exactly One Site

Chrome began rolling out third-party storage partitioning in Chrome 115. Google's documentation on storage partitioning describes storage written by an embedded third-party context being keyed by the top-level site, with an additional "ancestor bit" set when any document between the frame and the top-level site is cross-site. The affected list is long: localStorage, sessionStorage, IndexedDB, quota, BroadcastChannel, SharedWorkers, WebLocks and service workers.

Three consequences that matter to a portal operator:

  • A game served from the licensor's CDN and embedded on your portal writes its save data into a partition keyed to your site. The same title on another operator's portal is a different partition. Players do not carry progress between licensees โ€” which is usually exactly what you want, and occasionally a surprise to whoever promised cross-portal continuity.
  • Progress does not follow the player across top-level sites you own either. If your consumer portal and your carrier-branded portal sit on different registrable domains, they are different partitions, and the same person starts from zero on the second one.
  • Either way the save data is not yours to read. It belongs to the game's origin, partitioned or not. "We can just look at their localStorage" is not an option that exists.

One clarification, because operators conflate these constantly: Google announced in April 2025 that it will continue to offer third-party cookies in Chrome and will not ship a standalone prompt for them. That decision is about cookies. Storage partitioning is a separate mechanism, and it shipped.

๐Ÿ—‚๏ธ Self-Hosting Turns Your CDN Log Into Crude Telemetry

If your licence lets you host builds on your own infrastructure, the measurement picture changes twice over.

The obvious change: serve the game from your own origin and the boundary disappears, along with every restriction above. Your analytics runs inside the game document because there is no longer a cross-origin frame.

The less obvious change is available even if you keep the game on a separate subdomain for isolation. Your request logs become a depth signal. Games load assets progressively โ€” level packs, later sprite atlases, boss music, bonus-round audio. If four percent of sessions ever request the level-three bundle, you have located your drop-off without a single SDK event. It is noisy, because caching and prefetching both distort it, and it is directionally real in a way that page views are not. Sort your catalogue by "share of sessions that requested a late-stage asset" and you will get a very different ranking than the one in the meeting.

All of which is a licence-scope conversation: hosting rights, permission to modify builds, permission to add your own instrumentation. Ask for all three together, because they are cheap to grant at negotiation and expensive to retrofit.

โš ๏ธ Four Decisions Operators Make on Data They Do Not Have

The measurement gap only matters because of what gets decided on top of it.

  1. Culling the catalogue. Removing the bottom hundred titles by page views removes the hundred titles your merchandising buried. Some of them are your best-retaining games, sitting on page nine.
  2. Settling revenue share on in-frame ad numbers. If the ad calls fire inside the frame against the licensor's ad account, the licensor's report is the only record that exists. That is workable โ€” it is how a lot of the market runs โ€” but it belongs in the contract as a reporting cadence, a granularity commitment and an audit right, not as a monthly PDF you have no way to check.
  3. Buying breadth instead of fixing depth. Page views tell you the catalogue is thin, so you license more titles. They cannot tell you that your ten most-clicked games fail on first input on a four-gigabyte Android device, which is the actual reason the numbers are flat.
  4. Prioritising localisation and features. Which titles deserve translated builds is a question about who plays them and for how long. Without in-game events you are choosing from a popularity list you generated yourself.

๐Ÿ“‹ The Measurement Clauses to Raise Before You Sign

Bring these to the licensor while you still have leverage:

  • Do the builds emit lifecycle events to the parent frame โ€” and across what share of the catalogue, by build vintage?
  • May we modify builds to add a postMessage bridge or our own analytics?
  • May we self-host, and on which domains? Does that include a carrier-branded or white-label deployment on a separate domain?
  • Which analytics and ad SDKs are compiled into the builds, and which endpoints do they report to?
  • If ad revenue is shared, what is the reporting granularity, the cadence, and the audit right?
  • Who is responsible when a browser release breaks a title, and on what timeline?
  • Is there a replacement right if a title underperforms against a metric we can both see?

That last one is the tell. A licensor who is comfortable being measured will discuss a replacement right. A licensor who is not will explain why measurement is hard. It is hard โ€” that is the whole point of this post โ€” and it is not a reason to leave the question out of the agreement.

๐ŸŽฏ What a Licence Covers When You License HTML5 Games From a Direct Licensor

Forestry Games has operated since 2017 and licenses a catalogue of 1,049 titles spanning HTML5 and Android APK games, with titles also published on Google Play and the Apple App Store. Depending on scope, a licence can include HTML5 builds, APK builds, source where applicable, branding and rebranding rights and hosting arrangements, alongside distribution and monetization support rather than a handover of zip files. Because a share of the catalogue is developed in-house, questions about what a build emits and whether it may be modified have an answer rather than a forwarded email โ€” which is precisely the difference that decides whether the measurement clauses above are negotiable. You can browse the catalogue, look at what it means to license HTML5 games for a portal, or scope an APK game licensing conversation alongside it, since Android builds raise their own instrumentation questions.

๐Ÿงธ Licensing Branded Games for Campaigns, Portals and Events

Forestry Games also works with branded IP and has brand partnerships including Disney, Nickelodeon, Cartoon Network and Warner Bros. Businesses can license branded game content through Forestry Games for marketing campaigns, white-label game portals, live events and mobile apps. Branded titles add an approval layer that generic catalogue titles do not have, and that layer reaches measurement too โ€” what you may instrument, what you may report externally, and what analytics may run inside a build carrying someone else's characters are all questions to settle during scoping rather than after launch. The practical next step is to send a scope covering territories, platforms, term and formats, and to ask for a portal demo or licence scope that includes the event and hosting questions from the checklist above.

๐Ÿงญ Where to Start

Do the free thing first. Add a postMessage listener to your game pages, log everything that arrives including messages you do not recognise, and leave it running for a week. You will find out for nothing which parts of your catalogue already speak, and that answer sharpens every question you then put to your licensor.

Then stop treating the page-view ranking as a ranking of games. Label it "merchandising performance" in the deck, put it next to average engagement time, and be honest in the meeting that the second column is the only one describing what happened after the click. Everything better than that has to be negotiated into the licence โ€” which means the time to fix your measurement problem is while the agreement is still a draft, not when the renewal comes round and nobody can say which hundred titles earned their place.

Related Reading

An Employee Is Not an Audience: What Breaks When a Licensed Game Catalogue Goes Behind the Firewall

Two-Thirds of Brazil's Recurring-Pix Payers Never Subscribed to Anything. That Is Who Buys Your Games Portal Now.

A Click Costs $1.63. The Biggest Web Game Portals Buy Almost None of Their Traffic.

Every Captive Portal Vendor Sells 'Gamification.' iOS's Mini-Browser Is 900ร—572 Pixels.

Google's Game Ad Formats Are Application-Only. Model Your Portal Revenue for a No.

Google Indexes One Copy of a Licensed Game Page. It Probably Isn't Yours.

Browse all posts โ†’