Runtime defense
Published
It is a reasonable-sounding request. You license your software by territory, or you have a distribution agreement that stops at a border, so you would like the JavaScript to refuse to run outside the regions you sell to. The option does not exist, and the reason it does not exist is more useful than the feature would have been.
The short answer, and the useful one
The short answer is that there is no geographic lock in the option set, and adding one would be selling a check that does not check anything. The useful answer is a bit longer, because the reason is worth understanding: it applies equally to every client-side restriction, including the ones that do exist and are worth using.
Here is the whole runtime lock family:
- Domain lock — the page hostname must appear in a list you configure.
- Browser lock — the browser must classify into one of a set you allow.
- Operating system lock — the platform must classify into one of a set you allow.
- Expiry date lock — the current date must be before a date you set.
- Start date lock — the current date must be after a date you set.
Notice what they have in common. Each one asks the browser a question and believes the answer. That is fine for the purposes they serve, and it is exactly why a geographic version of the same idea would be weaker than it sounds.
Every location signal a browser offers is a setting
If you wanted to write a country check in page script, these are the inputs available, and each has the same problem.
Time zone
The internationalisation API will tell you the configured zone, which feels like a location and is a preference. Changing it takes a few seconds in system settings, and because the same API is readable by anyone inspecting the page, a visitor can see precisely which value your check wants.
Language and locale
Also a setting, and a weak signal even when nobody is being evasive. Plenty of people run an English-configured browser everywhere in the world, and plenty of people in a country do not use its majority language.
The geolocation API
This one is a real position, subject to two conditions that remove it as an enforcement mechanism: the user must grant permission, and can simply refuse; and the developer tools in every major browser let a position be overridden outright. It is built for helping somebody, not for restricting them.
The IP address
The only signal in the list your code does not receive from the visitor, and consequently the only one worth acting on — but your page script never sees it. It is observed by your server or your content delivery network at request time, which is both earlier and more reliable than anything the page could do. Commercial virtual private networks still make it an approximation rather than a fact.
So a client-side geographic check would ask a question, accept the answer, and run after the file had already been delivered. There is no arrangement of those three properties that produces enforcement.
What the existing locks really assert
Since the same reasoning applies to the locks that do ship, it is worth being exact about their behaviour, because the details change how you should use them.
Domain lock
The guard reads the hostname of the document it is running in, lowercases it, and walks your comma-separated allowlist, optionally allowing subdomains of an entry. Two consequences follow. First, an empty hostname — a file opened directly from disk, or certain embedded and custom-scheme contexts — fires the failure action before the allowlist is examined at all, so a lock configured for production will also stop your own local preview. Second, because it reads the hostname of the document the code runs in, a page of yours embedded in somebody else’s site still reports your hostname and still passes. Framing is a response-header question rather than a build-option one.
Browser and operating system locks
Both classify the user agent string into a fixed vocabulary and compare against your list. The browser lock recognises edge, opera, firefox, internet explorer, chrome and safari, and where the browser exposes structured brand information it cross-checks the two, firing the failure action if they disagree. The operating system lock does the same over windows, macos, linux, android and ios, with a deliberate exemption for android reporting alongside linux. Anything unrecognised becomes unknown, and unknown is never in an allowlist, so an unusual runtime such as an embedded kiosk browser fails closed. That is the safe default and a common cause of surprise.
Date locks
The date comparison uses the date the device reports. A user who changes the system clock changes the result, which is the same category of limitation as everything else on this list, and it is entirely adequate for ending an evaluation build without a conversation.
Where geographic restriction belongs
Every workable version of this requirement moves the decision to somewhere the visitor does not control.
At the edge, on the response
Content delivery networks apply country rules to requests before a file is served. That is the correct layer for a blanket regional restriction, because it acts before delivery rather than after, and it costs nothing at runtime.
At the API, per operation
The stronger control, and the one that survives someone loading your application anyway. If the interesting operations require an authenticated call, and the account carries the territories it is licensed for, then the restriction is enforced where the value actually is. A visitor in an unlicensed region can load every file you serve and still accomplish nothing.
In the agreement
Territory clauses exist because technical restriction of software delivered to a user device has always been partial. Writing the licensed regions into the contract gives the restriction a basis that does not depend on a check running correctly in a browser you have never seen.
When the client-side locks are still worth turning on
None of this is an argument against the lock options. It is an argument about what they are for. They are friction and accident prevention, and by that standard they earn their place:
- A domain lock defeats the ordinary case of somebody copying your files to another host without editing them, which is what usually happens.
- A date lock ends an evaluation build cleanly and without a support ticket.
- A configured restriction is visible evidence of intent, which matters if you ever need to establish that a use was unauthorised.
- The failure action is configurable, so you can choose between stopping, blanking the interface, redirecting, or calling back into your own code to record the event.
What none of them is, and what a geographic lock would especially not be, is enforcement. Configure them for the honest majority, put the authority behind an authenticated endpoint, and let the contract cover the rest.
Frequently asked questions
Is there a country or region lock in JavaScript Obfuscator?
No. The runtime lock family consists of a domain lock, a browser lock, an operating system lock, an expiry date lock and a start date lock. None of them is geographic, and that omission is deliberate rather than an oversight. A geographic check in page script would have to rely on a signal the browser reports, and every such signal is under the control of the person you would be trying to restrict.
Why not just check the time zone or the browser language?
Because both are user settings rather than measurements. The reported time zone comes from the device configuration and can be changed in a few clicks, and the browser also exposes it to any script that asks, so a determined visitor can see exactly what your check reads. Language preference is set in the same way and is a poor proxy for location even when it is honest, since people routinely use a browser configured in one language while living somewhere else.
What about looking up the visitor IP address?
That is a genuinely useful signal, and it belongs on the server or at your content delivery edge rather than in page script. By the time your JavaScript is running, the file has already been delivered, so a script that discovers it is in the wrong country is reacting after the thing you wanted to prevent has happened. Commercial virtual private networks also make address-based location an approximation rather than a fact, which is fine for routing and analytics and weak as an enforcement boundary.
Does the geolocation API give a reliable position?
It gives a position the user chose to provide. The browser requires explicit permission, so a visitor can simply decline and your code learns nothing, and the developer tools in every major browser allow a position to be overridden for testing, which works just as well outside testing. It is a good feature for helping someone find a nearby store and a poor one for deciding whether they are allowed to use your software.
So what does the domain lock actually verify?
That the hostname of the document running the guard appears in a list you configured. It reads the location hostname, lowercases it, and compares against your allowlist, optionally matching subdomains. Two behaviours are worth knowing. An empty hostname, which is what you get from a file opened off disk or from certain embedded contexts, triggers the failure action before the allowlist is consulted. And because the check reads the hostname of the document the code runs in, an embedded copy served from your own host still matches, so it is not a control against framing.
How do the browser and operating system locks decide what they are looking at?
By classifying the user agent string into a small set of known values, then comparing against your list. The browser lock recognises edge, opera, firefox, internet explorer, chrome and safari, and additionally cross-checks the browser brand data where the browser provides it, firing the failure action when the two disagree. The operating system lock works the same way over windows, macos, linux, android and ios, with an exemption for the android-on-linux combination that is normal rather than suspicious. Anything unrecognised classifies as unknown, which never appears in an allowlist, so unusual runtimes fail closed.
If the locks are all checkable by the user, why enable them at all?
Because deterrence and accident prevention are worth something even when circumvention is possible. A domain lock stops a copied site from working when someone rehosts your files without editing them, which is the common case rather than the sophisticated one. A date lock ends a trial or an evaluation build without a support conversation. And configuring a restriction is a visible statement of intent, which has value if you ever need to argue that use of your code was unauthorised. The mistake is treating any of them as enforcement of a licence rather than as friction supporting one.
How should regional licensing actually be enforced?
In the place that decides, not in the file that renders. Serve the application from an edge or server layer that can apply country rules to the response, authorise every meaningful operation against an account whose entitlements record the regions it covers, and write the territory into the contract so the restriction has a basis outside your code. The browser then displays whatever your server was willing to authorise, which is a design that holds up whether or not the visitor is honest about where they are.
Related reading