Case study
Geofencing a live video player to enforce content licensing
Regional licensing terms for NHK programming on Link TV were not being enforced by the player. I designed and built the geofence that closed that exposure.
The constraint
Link TV carried programming from NHK World under a license that limited where it could be viewed. The license covered only the Southern California zip codes inside Link TV’s broadcast area. The player enforced none of it. Anyone with the URL could watch from anywhere.
That is a legal exposure, not a bug. Legal needed it closed, and the enforcement had to be something we could show the licensor, not just assert. There was a second constraint from the business side: no additional spend on the streaming platform. Whatever we built had to run on what we already had.
What made it non-obvious:
- The rule was at the zip-code level. Not country, not state. IP-to-location databases are wrong at the edges even for countries. At postal-code granularity their accuracy drops sharply, mobile carriers route traffic across regions, and VPNs exist. “Enforce the license” could not mean “be 100% accurate.” It had to mean “apply a defensible, documented standard.”
- The rule had to apply itself. Only some content on the channel was restricted, so a site-wide block was the wrong shape. But nobody could be in the loop either: not an editor flagging each airing, not a viewer asked to do anything. The restriction had to attach to the content itself, so that any time a restricted show played, anywhere on the site, the rule came with it.
- False positives are a public-media problem. Locking out a legitimate viewer in Los Angeles is a support ticket and a reputational cost for a nonprofit broadcaster. A blocked viewer had to see a clear explanation, not a broken player.
Options considered
- Block at the CDN edge by region. Cheapest to turn on, but it works at country or state level, not zip code, and it does not know which show is playing. Wrong shape for this license.
- Check in the browser only. Call a geolocation service from the player on load and hide the stream if the viewer is outside the area. Fast to build, no backend change. But it is enforcement by suggestion: the stream URL is still in the page source, and anyone who disables the script gets the content. Not something you can show a licensor as compliance.
- Gate the stream server-side. The player asks the backend for the stream URL. The backend resolves the viewer’s location, checks it against the territory rule attached to that show in the CMS, and either returns the URL or refuses. The page never contains a playable URL for a blocked viewer. Costs: a new backend call in the path of every play, a geolocation dependency with its own latency and failure modes, and cache rules to get right.
- Do nothing technical; renegotiate the license. A real option for the business. It was off the table because the licensor’s territory terms for these shows were fixed.
What was chosen and why
Option 3, server-side gating, with the territory rule stored on the show record in Brightspot CMS rather than in code.
The tradeoff accepted: a new dependency in the hot path of every playback, and the latency of a location lookup before the stream starts, in exchange for enforcement that lives on the server, where the decision can be recorded. Options 1 and 2 were rejected because they could not produce evidence, and option 1 could not match a zip-level rule at all. If the licensor asks how we know a viewer in Northern California could not watch, the answer has to come from the server that refused the request, not from a screenshot of a blocked player.
Two location tiers, because one was not enough. MaxMind GeoIP2, queried from the Java backend, was the primary check. It was already licensed, so it cost nothing extra, and it needed no interaction from the viewer. But IP geolocation could not reliably resolve zip codes at city boundaries, and the license boundary was a city boundary. So when the IP result was unavailable or fell in an ambiguous area, the player fell back to the browser’s Geolocation API, which uses the device’s own location and is far more precise. The viewer has to grant permission. A viewer who declines does not get the stream. That is the answer to “fail open or fail closed”: the design never fails open, but it gives the viewer a way to prove they are in the area before it refuses.
Design details:
- Matched on: zip code, against the list stored on the show record.
- Where the rule lives: a field on the show record in Brightspot CMS. Editors change territories without a deploy.
- Cache behavior: the public page stayed cacheable. Only the gating call was excluded from caching, so a decision made for one viewer could never be served to another.
- What a blocked viewer sees: an error message explaining why the video cannot be played in their location.
- Logging: the decision was to only log error messages, filtering out PII data using Java Logger class.
- Testing: boundary cases at city limits were the hard part. We tested with VPN exits outside the area, BrowserStack, and staff on real devices at known addresses near the boundary.
What happened
- Shipped September 2022, on schedule. Demo: https://youtu.be/eQYippL9BH8
- Closed the standing licensing exposure on NHK content for Link TV. Legal confirmed the change met the license terms.
- The IP tier alone failed the city-limits tests: MaxMind could not consistently place viewers near the boundary in the right zip code. That finding is what produced the device-location fallback rather than a looser rule.
If I did it again
I’d build the server-side IP tier first and treat device location strictly as the fallback for boundary cases, so that no zip-mapping data or decision logic ever lives in the browser.
Open to technical lead and solutions architect roles, remote. Get in touch or read the other case studies.
