Salesforce · ServiceNow · Power Apps · Mendix · OutSystems

The platform owns your build, your runtime, and the names your code answers to.

Every other target on this site assumes you run a build and produce an artifact. A low-code platform frequently takes that away: you hand over source, the vendor transpiles and bundles it, and what reaches the browser was assembled by somebody else. That single fact decides which parts of your project can be protected at all — and for the parts that can, a component framework that calls your methods by name turns the most common setting on this site into a failure with no error message.

The Short Version

Find the artifact · Exclude the framework names · Expect a tenant hostname

Three decisions carry the whole configuration, and the first one is not a setting at all.

Only uploaded artifacts can be protectedManaged source is transpiled by the vendor, so no step of yours ever holds it.
The framework calls you by nameLifecycle hooks and template bindings are a contract; renaming one side breaks it silently.
Sandbox refreshes move the hostnameA domain lock that was correct last week fails after a refresh nobody announced.
Why This Page Exists

The distribution model where you do not own the pipeline

This site has a page for most ways JavaScript reaches a user, and nearly all of them share an assumption: somewhere there is a build, and you control it. Low-code and application platforms break that assumption in a specific way. The vendor supplies the framework, the compiler, the bundler, the content security policy and the hostname. Your code is a guest in a pipeline somebody else designed, and the useful advice on this page follows from that rather than from the JavaScript itself.

The vendor compiles what you write

Managed source is parsed, transpiled and bundled by the platform. There is no moment where a file of yours exists in final form on a machine you control, which is where a protection step would have to run.

The framework reaches into your code

Component models call lifecycle methods by name, templates bind to properties by name, and platform metadata names your handlers. Those names are interface, not implementation.

The environment is assigned, not chosen

Hostnames, security policy and the shell around your component all come from the vendor and change on their schedule. Runtime guards that read the environment inherit that instability.

Find The Insertion Point First

Your project is two halves, and only one can be protected

Before any option matters, sort your code into the half the platform builds and the half you build. This is the single most useful hour of work on the whole topic, and most teams discover the split is not where they assumed.

Managed source, which you cannot transform

Scripts written in the vendor's editor, component classes committed to the platform's own repository, expression-language snippets, inline handlers attached to a form. The platform receives your text and does everything after that. Nothing in a build pipeline of yours ever touches it, so protection is not an option that is switched off — it is a step with nowhere to stand.

Uploaded artifacts, which behave normally

A bundle you build locally and upload as a static resource, a packaged custom control produced by an ordinary npm build, a JavaScript module distributed inside an installable package. These are built on your machine or in your pipeline, so a protection step goes exactly where it goes for any other project, immediately before the artifact is packaged.

The consequence for design, not just for build

If a piece of logic is worth protecting and currently lives in managed source, the question is whether it belongs in a bundled artifact instead — or, far more often, whether it belongs on the server. Moving a decision out of a platform script into a service endpoint answers the exposure question completely rather than reducing it.

Watch for a re-processing step after yours

Some platforms minify, transpile or lint what you upload. A transformation applied after your protection step can undo part of it or fail on it, and it happens silently. Deploy a protected artifact to a sandbox and read back what is actually served before you trust the round trip.

The Silent Failure

The framework calls your methods by name

This is the defect that brings people to a support channel, and it produces no error anywhere. It is the same shape as the problem hypermedia and attribute-driven frameworks have, arriving from a different direction: a name written outside your JavaScript, matched as text by something that never sees your build configuration.

Lifecycle hooks are an interface

A component model invokes the methods it expects to find on your class. Rename them and the framework looks for a name that is no longer there. It does not throw; it simply never calls you, so the component mounts and stays inert.

Template bindings read property names

Markup that references a property is resolved at run time against the object your class produced. Member renaming rewrites the property and leaves the markup, which the protector never parsed, pointing at the old name.

Metadata names your handlers

Flow definitions, action configurations and component descriptors declare handler names as text in files outside your source. Those declarations are matched literally, so both renaming and the string transforms can break them.

The fix is an exclusion list, kept next to the metadata

Member protection is designed to be pointed at what you choose rather than applied to everything. Put every framework-facing name into the reserved-name configuration, and put any literal the platform matches on into the reserved strings so the string transforms leave it verbatim. The list is short. What makes it work is reviewing it whenever the metadata changes, which means keeping it in that review rather than in a build file nobody opens.

Shrink the surface before you list it

A long exclusion list is a sign that too much of your component is public to the framework. Exposing one namespace object per feature, with everything else private behind it, makes the list short enough to keep correct and leaves far more of the code eligible for renaming. That is a design improvement that happens to make protection work better, which is the right order.

What Is Actually At Risk

Authentication changes who reads it, not whether they can

Teams often conclude that platform code needs no protection because it sits behind a login. That is worth examining rather than assuming, because the population with a login is usually larger and more varied than the mental picture of "our staff".

Everyone with a seat, not everyone on your team

Licensed users, contractors, integration accounts, partners in a community or portal, and people whose access outlived the role that justified it. Any of them can open the network panel. This is the insider case, and it is the honest reason to bother.

The logic is unusually sensitive

Internal applications encode approval thresholds, discount authority, eligibility rules and routing logic. That is exactly the category that is worth reading for someone already inside, and it is more consequential than the front-end code of a public marketing site.

A client-side check is still a client-side check

A limit enforced in a component is a limit the user can edit. Protection raises the cost of finding it and changes nothing about where the decision is made. Approval and entitlement logic belongs in a service call your platform answers.

Runtime Options On A Tenant

Most of the runtime defenses are unavailable, and the build says so

Runtime guards assume a browser page whose environment you configured. A platform tenancy is a browser page somebody else configured, with a hostname they assigned and a security policy they set, so it is worth knowing exactly what each guard reads before enabling it.

The domain lock works, and it is high maintenance

The guard reads the browser's hostname and compares it against your allowlist. On a hosted platform that hostname is vendor-assigned, differs across production and every sandbox, and changes when a sandbox is refreshed or an org is migrated. A lock that was correct last week then fails for real users on a schedule you did not set. If you use it, enumerate the sandbox patterns deliberately and pick a failure action that degrades rather than one that throws.

The evaluation-based wrappers are usually out

The self-defending wrapper, the self-healing recovery wrapper and the anti-tampering monitor all evaluate code at run time, and the engine warns during the build that they need a policy permitting it. Platform runtimes commonly enforce a strict policy that forbids exactly that. The same three are skipped automatically for ES module source, with their own warning, and modern component models are ES modules — so on much of this work they were never applied at all.

Console suppression costs you colleagues' time

The option that empties the console methods deletes the diagnostic channel an internal user can actually send you. For an application whose users sit in your own organisation and are routinely asked for a screenshot of the error, that trade is close to indefensible.

Developer-tool blocking is not your window

The keyboard and context-menu blocking option cancels events inside a shell the vendor owns. It interferes with platform affordances and with assistive technology, and it does not stop anyone reading a bundle their browser has already downloaded. Leave it off here.

The Case With The Strongest Argument

Packaged components you distribute to other tenants

Everything above is about code that stays inside your own organisation. The moment you package a component and install it into somebody else's tenancy, the calculation changes, because your artifact now lives somewhere you have no administrative reach at all.

A subscriber's org is a published artifact

The installing organisation can read what it installed, and so can anyone they grant access to. That is the same position as a marketplace add-in, minus the reviewer, and protection is doing real work against a competitor lifting your implementation.

Pin a seed so upgrades diff

Identifier generation is randomised per build by default, so two builds of unchanged source differ everywhere. A fixed seed makes an upgrade diff to roughly the change you made, which matters whenever a subscriber or a platform review compares versions. See reproducible builds.

Watermark the release

A keyed tag embedded in the build lets you attribute a copy you find later to the release it came from. It proves origin rather than preventing copying, which is the correct expectation, and it pairs with a manifest recording the source and output hashes per file.

Questions

Frequently asked questions

Where does a protection step even go on a low-code platform?

Wherever you own a build, and nowhere else. These platforms split into two halves and the halves behave completely differently. Managed source is code you paste or commit into the vendor's editor: the platform parses it, transpiles it, bundles it and serves it, and there is no point in that chain where your artifact exists for you to transform. Uploaded artifacts are the other half, where you run your own build locally and upload the result as a static resource, a packaged control or a custom module. That second half is a normal build pipeline and takes a protection step exactly like any other. The first question to answer about your own project is which half each piece of your code lives in, because the answer decides what is possible before any option matters.

Why does member renaming break a low-code component so badly?

Because the framework calls your code by name, and those names are a contract rather than an implementation detail. A component model invokes lifecycle methods it expects to find, a template binds to property names it reads from your class, a platform action dispatches to a handler whose name is declared in metadata somewhere outside the file. Member renaming rewrites property access, so a blanket setting renames one side of that contract and leaves the other side pointing at a name that no longer exists. Nothing errors at build time and nothing errors at parse time. The component mounts, the panel draws, and one region quietly does nothing. Use the rule-based member selection and keep every framework-facing name out of scope.

Is my platform code even exposed? It sits behind a login.

It is exposed to everyone who can log in, which is a different and usually larger group than you first picture. An internal application is readable by every licensed user in the org, every contractor with a seat, every partner in a community or portal, and anyone who has kept a session from a role they no longer hold. That is the insider and partner threat model rather than the open-web one, and it is the honest reason to protect this code: not because a stranger will find it, but because the person reading it is already inside and is looking at the logic that decides approvals, limits, pricing or eligibility. Authentication changes who reads your bundle. It does not change that they can.

Does the domain lock work on a tenant hostname?

It works, but it is high maintenance here in a way it is not elsewhere, and the maintenance falls on a schedule you do not set. The guard reads the browser's hostname and compares it against your allowlist. On a hosted platform that hostname is assigned by the vendor, differs between production and every sandbox, and changes when a sandbox is refreshed or an org is migrated. So a lock that is correct on Monday fails after a refresh nobody told you about, and the failure lands on users rather than on a build. If you use it, include every sandbox pattern deliberately, keep the list next to whatever document records your org topology, and choose a failure action that degrades rather than one that throws.

Which runtime defenses can I actually use inside a platform runtime?

Fewer than the option list suggests, and the build tells you which. Three of them, the self-defending wrapper, the self-healing recovery wrapper and the anti-tampering monitor, evaluate code at run time, and the engine emits a warning that they need a policy permitting dynamic evaluation. Platform runtimes commonly enforce a strict content security policy, which is exactly the policy that forbids it. Those same three are also skipped automatically when the source is an ES module, with their own warning, because they are classic-script wrappers that would break import linking. Modern component models are ES modules, so on a lot of low-code work those options were never applied even where the policy would have allowed them. Read the build warnings instead of assuming the setting took effect.

What about blocking the console or developer tools on an internal app?

Both are worse choices here than almost anywhere else on this site. Emptying the console methods removes the one diagnostic channel an internal user can send you, and internal users are the population most likely to be asked for a screenshot of an error. Blocking keyboard shortcuts and the context menu cancels events inside an application whose shell belongs to the vendor, which interferes with platform affordances and with assistive technology, and it does nothing about a bundle that has already been downloaded. Neither option prevents reading. Both cost you support time from colleagues.

How do we keep platform metadata and our build in agreement?

By treating every externally declared identifier as an exclusion and reviewing the list whenever the metadata changes. Low-code platforms keep a lot of your program outside your source: handler names in a flow definition, field and object API names, action identifiers, event names, component attributes declared in a configuration file. All of those are matched as text by something you do not control. Put the names in the reserved-name configuration so renaming leaves them alone, put any literal the platform matches on into the reserved-strings configuration so the string transforms leave it alone, and keep both lists in the same review as the metadata rather than in a build file nobody opens.

Is it worth protecting an ISV package we distribute to other orgs?

That is the case with the strongest argument on this page, because it is the one where your code leaves your own tenancy. A packaged component installed into somebody else's org is a published artifact in every practical sense: the subscriber can read it, and so can anyone they grant access to. Protection raises the cost of lifting your implementation into a competing package, and a watermark lets you attribute a copy you find later to the build it came from. Pin a seed as well, so the diff between two releases shows the change you made rather than a total rewrite, which matters when a subscriber or a platform review looks at an upgrade.

Will the platform reject or re-process protected code?

It may do either, and the only reliable answer comes from your own vendor rather than from us, so confirm it before you build a release process on top of protection. What is consistent everywhere is the mechanism. Platforms of this kind commonly lint, statically analyze, transpile or re-minify what you give them, and any of those steps reads your code. Heavily transformed output is harder for a static analyzer to interpret and resembles the shape that security tooling is trained to flag, and a re-processing step applied after your protection step can undo part of it or fail on it. Test the round trip on a real deployment rather than assuming your artifact arrives byte for byte.

What is a sensible order of operations for a release?

Five steps. First, split your inventory into managed source and uploaded artifacts, because only the second half can be protected at all. Second, write down every name the platform reaches into your code by, from lifecycle hooks to metadata-declared handlers, and turn that list into your exclusion configuration. Third, run every tool that works by reading code, including composition analysis and secret scanning, against the artifact before it is transformed. Fourth, protect with a fixed seed and deploy to a sandbox, then exercise the paths that touch platform APIs rather than only loading the page. Fifth, keep the symbol map and the build manifest for the exact deployed version, because a defect report from an internal user of a protected component is otherwise close to undebuggable.

Related Guides

Protecting other JavaScript targets

Projects with no build step

The neighbouring case: code that reaches a page without a pipeline, and what protects it when there is nowhere obvious to insert a step.

Marketplace add-ins

The other model where a third party reviews your submission and a host application decides what your code may do.

Attribute-driven frameworks

The same silent failure from a different direction, where behaviour is declared in markup the protector never parses.

Rule-based member protection

The mechanism that makes renaming safe on a framework-driven codebase, pointed at what you choose rather than everything.

Next Step

Two lists, then a sandbox deployment

Write the first list by sorting every piece of client-side code you own into managed source and uploaded artifacts, because that decides what is even eligible. Write the second by walking your metadata and collecting every name the platform reaches into your code by, then turn it into your reserved names and reserved strings. Protect one artifact with a fixed seed, deploy it to a sandbox, and exercise the paths that call platform APIs rather than just loading the page — that last step is where a silent renaming failure shows itself, and it is the only place it will.