ERPNext client scripts for form logic

Client scripts add JavaScript behaviour to ERPNext forms without a custom app. This page explains when they are enough, the common patterns, and how to configure and test them.

On this page

When ERPNext client scripts are enough for form logic

A team that needs a form to react to user input, such as filtering a linked field by company or showing a button only when a document is submitted, can usually solve it with ERPNext client scripts. A client script is JavaScript that runs in the browser when a user opens or edits a form. It is the right tool for behaviour that exists only to help a person fill in a document: hiding or showing fields, setting default values in the open form, narrowing the options in a link field, confirming a value before save, and adding custom buttons. Client scripts are written in the Desk interface and attached to a DocType, so they need no custom app and no change to ERPNext's own code. Confirm the exact event names and helper functions for your version in the Frappe Framework documentation before you write the first script, because the API differs between major releases.

The boundary is the important decision. A client script only runs when a person is using the form in a browser. Data created through the REST API, the Data Import tool, a bench console, or another integration bypasses it entirely. So any rule that must hold for every record, such as a credit limit check, a mandatory tax field for a given territory, or a status transition that affects stock or accounting, belongs in a server-side mechanism. In ERPNext that is usually a server script, a controller override in a custom app, or a validation the data model enforces. Treat a client script as a usability layer on top of server-side validation, never as the only control. If you find yourself writing a client script to block a bad value, ask what happens when the same record arrives by import, and move that check to the server.

Before you commit to client scripts, list each piece of form logic and mark whether it is a convenience or a control. Convenience logic is safe in a client script and easy to change later. Control logic needs a server-side check plus, optionally, a client-side hint for faster feedback. Ask your implementation partner or internal ERPNext administrator to confirm which events and settings apply on your version, and test each rule with an import or API call as well as with a browser session. Scripts that depend on the Desk environment also need to be stored so they survive an upgrade or move between sites, which is covered in the version control section of this guide.

Which form changes fit a client script and which need a server-side or app solution

Filtering link fields and showing or hiding fields based on other values are the most common reasons to write a client script. These changes only affect what a user sees and can select in the form, so the browser is the right place for them. A client script can narrow the options a link field offers, for example limiting a Customer list to a company, and can toggle a section when a checkbox changes. Nothing is enforced here, so the filter does not stop data entered through the API, the Data Import tool or another script.

  • Good fit: hiding or showing fields, setting read-only state, and narrowing link queries for the person using the form.
  • Not enough alone: if a value must be valid for every record, add a server-side validation so that imports and API writes are checked too.
  • Data Import tool: imported rows do not run form-level client logic, so confirm how the import path handles the same fields.
  • Version differences: confirm the exact filter and visibility hooks available in your ERPNext version and whether they behave the same on mobile views.
  • Testing: check the form on each role that will see it, because permissions can hide fields that the script tries to set.

Before you rely on a filter, list every path that can create or change the field, not only the desk form.

Client script configuration options and when each fits

This table compares the main choices when configuring an ERPNext client script: the DocType it attaches to, the form events it hooks, its scope, and whether it is enabled. Read each row as a decision, then check the trade-off column before deciding where the logic should live. The main takeaway is that a client script shapes the browser experience but does not enforce rules on its own.

Configuration choiceWhen it fitsWhat it trades away
DocType the script attaches toStandard forms where users enter data, such as Sales Invoice or Item, and where the change is purely about layout or guidanceChanges apply only where the form loads; a custom DocType needs its own script, so keep a list of every attached DocType
Refresh event handlerAdding custom buttons, hiding sections or setting read-only state based on the document's current statusRuns each time the form renders, so heavy calls here slow every open; keep logic light and check status fields first
Field change handlerFiltering linked fields, auto-filling a value when a user selects a customer or item, or recalculating a total in the formFires only when a user edits the field in the browser, so values set by import, API or another script will not trigger it
Form-level scopeBehaviour that depends on several fields or the document as a whole, such as a warning when a combination of fields is invalidMore code to review and test per form; changes to the form layout can break logic that reads field names
Field-level scopeA single field needs a filter or default that is easy to name and reuse across the same formSeveral field-level handlers on one form can interact in ways that are hard to trace; document their order
Enabled stateTurning a script on for testing or a rollout, or keeping it in the database while you decide whether to move it into an appA disabled script is easy to forget; record who disabled it and why, and confirm it is off on each site
Browser-only enforcementUser guidance, helpful defaults and convenience buttons that do not change what is allowed to be savedUsers with API access, data import or a different client can bypass the script, so validation must also exist server side
Logic that must hold for every writeNot a good fit for a client script; move it to a server script, a custom app or the standard validation pathServer-side logic takes more effort to build and test, and server scripts depend on the enabled setting described in the Frappe documentation

How to build and check a client script in ERPNext

This sequence takes a client script from a confirmed target form to a tested, version-controlled change that behaves the same for every role that uses the form. Each step ends with a check so problems surface on a test site rather than in production.

  1. Confirm the target DocType and version

    Identify the exact DocType, such as Sales Invoice or Purchase Order, and the ERPNext major version running on the test site. Client scripts attach to a DocType, and form behaviour can differ between major versions, so record both before writing anything. Ask the administrator to confirm which version is in production and whether the site is self-hosted or on Frappe Cloud. Done when you can state the DocType, the version and the site name in one line.

  2. Identify the form events the logic needs

    List the moments the logic must react to, such as the form loading, a field value changing, a row being added to a child table, or a button being needed. Map each requirement to a form event and write down which fields it reads and which it sets. Keep the list short, because every extra handler adds behaviour that must be tested later. Done when each rule in the requirement has one named event and one named field.

  3. Write and save the script on a test site

    Create the Client Script record on a test site, select the DocType, choose the script type (Form or List view), and write the handlers. Save the record and reload the form, since changes may not appear until the page reloads. Use the same field names the form shows in its Customize Form view, not labels. Done when the form loads without a visible error and the new behaviour appears on a sample record.

  4. Verify filters and buttons for each role

    Log in as each role that uses the form and repeat the same actions. For a field filter, confirm that a restricted role sees only the records it is allowed to see in the linked field, and that an unrestricted role still sees the full list. For a custom button, confirm it appears only for the intended roles and that clicking it produces the expected change. Done when each role's result matches the requirement and you have noted any role that behaves differently.

  5. Check the browser console for errors

    Open the browser developer tools on each form path you tested and read the console for JavaScript errors and failed requests. Repeat the check in at least two browsers that your users run, and note any browser-specific differences in layout or button behaviour. Errors that do not block the screen can still stop a later handler from running, so do not skip this check. Done when the console shows no errors on the tested paths, or each remaining error has been traced and explained.

  6. Confirm behaviour survives a reload and an upgrade test

    Create, save, submit and amend a test record, then reload the page and confirm the script still runs at each stage. Where the site allows it, repeat the test on a copy of the site after a minor update, since a change in the framework or in the form can break handlers that worked before. Done when the behaviour holds across the document lifecycle and the copy-after-update test produces no new errors.

  7. Move the script into version control or a custom app

    Export the Client Script record so the code lives in version control rather than only in the database, either through the customization export workflow or by placing it in a custom app. Record who owns the change, the version it was tested on and the roles it was verified for, and deploy it to production through the same path as other changes. Done when the script can be restored from the repository to a fresh test site and passes the role checks from the earlier steps.

Common client script patterns: field filters and custom buttons

The two patterns teams request most from client scripts are restricting the options of a linked field based on another field, and adding a custom button that either calls a server method or opens a dialog. Both depend on the DocType's field names, its link targets and the role permissions of the person using the form. A field filter needs the controlling field to exist on the same DocType, and the filtered link field must point to a DocType the user can read. A custom button needs a clear condition for when it appears, such as a document status or a docstatus value, so that it is not offered on documents where the action makes no sense. For each button, confirm which server method it calls, whether that method checks permissions itself, and which roles can reach it.

A filter set in the browser only narrows what the form displays. It does not stop a user with API access, a data import or another script from saving a value outside that list. Any rule that matters for accounting, stock or approvals belongs in a permission rule, a validation on the server, or a user or role permission, and the client script should only make the correct path easier to follow. The same applies to buttons: hiding a button from one role does not block that role from calling the underlying method. Test each pattern with a user who holds the minimum roles, and confirm that the server rejects the action when it is called directly.

Before building either pattern, list the linked fields and buttons the business needs, then check each one against the role matrix in the ERPNext roles and permissions setup. Ask the team that owns the process to confirm which values are valid in each case, because a filter that is too narrow can block legitimate invoices and orders. Keep a short test script for each form that covers the filtered and unfiltered cases, and rerun it after every ERPNext minor release, since form behaviour can change between versions.

How to test client scripts across browsers and roles

Client scripts run in the browser, so their behaviour depends on the browser, the user's role, the form state and the ERPNext version underneath them. The checks below cover the risks that most often make a script work for the developer and fail for everyone else.

Desk UI browser differences

Client scripts change Desk forms through the frappe.ui and form APIs, and rendering can differ between current Chrome, Edge, Firefox and Safari. Test each script in every browser your users run, on the same form, with the same data. Check that dropdown filters open, custom buttons appear in the Actions or Create menus where expected, and dialogs can be dismissed with the keyboard. Record the browser version alongside each result so a later failure can be traced.

Cache and stale script after edits

After you change a client script, a browser may keep serving the old version, and the Desk may show behaviour from before the edit. Hard-refresh the page, clear site cache with the bench clear-cache command on your test site, and reload in a private window before you judge a fix. Confirm the saved script is the one running by adding a temporary, clearly named log line. Remove it before promotion so production logs stay clean.

Role-specific visibility

A script that hides a field or button for one role can leave another role with an empty or broken form. Log in as each role that touches the DocType, including users with restricted user permissions and those limited to a single company. Confirm that fields set read-only or hidden by the script match what the role permissions allow, and that the server still rejects changes the browser would block. Do not treat a hidden button as access control.

Narrow screens and mobile layouts

Desk forms reflow on tablets and phones, and custom buttons or dialogs added by a script can move, overlap or fall off screen. Test the forms your field staff use on a phone-sized viewport in browser developer tools and on a real device if one is available. Check that custom dialogs remain scrollable, that the primary action stays reachable, and that filters on link fields still open when the keyboard is visible.

Console errors and event order

Scripts that fail silently often leave a half-applied form state. Open the browser console on each test run and look for uncaught exceptions, failed network calls and warnings from the form lifecycle, such as code that reads a field before refresh has completed. Confirm that handlers for refresh, validate and field change run in the order your logic assumes, and that a failed server call does not leave buttons or fields in a stuck state.

Regression after minor releases

ERPNext ships frequent minor releases on both supported major versions, and a change in a standard form's JavaScript can break a script that depended on its internals. Keep a written test list for each script, run it on a staging copy of production after every minor upgrade, and compare the results with the previous run. Pin the ERPNext version you tested against in your change record, and check the release notes for changes to the forms your scripts touch.

Questions teams ask before building client scripts

How much effort does a simple client script take compared with a custom app?

A simple client script is usually a small, contained change: a few lines of JavaScript attached to one DocType, written and tested in the browser. A custom app is a larger undertaking because it adds a repository, a release process, deployment steps and ongoing maintenance. What drives the gap is the number of forms affected, whether the logic depends on server data, how many roles see the form, and whether the change must ship to several sites. Ask a partner to split the quote into logic written, forms covered, test cases and handover so you can compare options on the same basis.

Can our own team build ERPNext client scripts without a partner?

Yes, many teams do, provided someone understands the ERPNext form model and can read JavaScript. Useful skills include knowing how DocTypes, fields and child tables behave, working with the browser developer tools, and reading the Frappe client-side API. Someone must also own the work after go-live, because scripts change when fields are renamed or workflows change. If your team lacks these skills, a short scoped engagement can transfer knowledge while building the first scripts, which is often cheaper to plan than a long dependency on an outside team.

How long does testing client scripts take, and what does it depend on?

Testing time depends on how many forms and user roles are affected, how many states a document can pass through, and how many browsers and devices your users rely on. A script that only hides a field for one role needs far fewer cases than one that filters links, sets defaults and changes buttons across submitted and cancelled documents. Plan for a test pass in each supported browser, a regression check of the forms the script touches, and a retest after each ERPNext minor release. Ask the partner to list test cases in writing before work starts.

What do we need to provide for client script work?

The work moves faster when you provide a clear description of each rule, a sample of realistic records, and a role matrix showing who creates, edits, submits and cancels each document. You should also name a business owner who signs off each behaviour and gives an opinion on edge cases, such as partially received orders or foreign currency documents. Provide a test site with a copy of data that resembles production, and confirm who can approve changes. Without these inputs, testing tends to expand and sign-off takes longer.

Do client scripts survive ERPNext upgrades?

Client scripts are stored as records in the database and are generally not overwritten by an upgrade, but they can break when the underlying form, field names or client-side API change between versions. Treat each upgrade as a test event: run the scripts on a staging copy of the site, check the forms they touch, and review release notes for changes to the affected DocTypes. Plan for version control of script source, since database-only records are harder to review and move between environments. Confirm the specific upgrade path for your ERPNext version with your partner or the release notes before you commit to a schedule.

When should client script logic move to a server script or custom app?

Move logic to the server when a rule must hold regardless of how a document is entered, such as stock checks, calculations that must be auditable, or anything that depends on data a browser should not see. Client scripts only improve the experience in the form; they do not enforce rules for data imported, created through the API or changed by other scripts. Server scripts are disabled by default from version 15 and must be enabled with server_script_enabled, and they are not available on Frappe Cloud public shared benches. Decide early which rules are guidance and which are controls, because controls belong on the server.

Do client scripts help with compliance or access control?

Client scripts can hide or lock fields for usability, but they are not an access control mechanism, because a user can still reach data through other screens, reports or the API. Access rules belong in ERPNext role and permission settings, which your auditors will examine. If you rely on scripts for a control, document the expected behaviour, test it per role, and keep evidence of each test run. DeployOpen prepares systems, controls and evidence for compliance assessments, but independent auditors and certification bodies issue the actual assessments.

How DeployOpen scopes and delivers ERPNext client script work

DeployOpen plans, implements, tests, documents and supports ERPNext client scripts as part of a self-hosted ERPNext deployment in infrastructure you control. Each engagement starts from a written scope that names the forms, fields and users the scripts affect before any browser-side code is written.

How we scope

  • Inventory every form where client script logic is requested, with the DocTypes, fields and roles involved.
  • Decide with you whether a client script, a custom field, a property setter or a server-side change fits each case.
  • Agree browsers, ERPNext versions and test users in writing before work starts, since engagements are fixed-scope.

How we build

  • Write client scripts against the form events and field filters your team has approved, keeping logic readable and documented.
  • Version scripts in the same change process as other customizations so each edit can be reviewed and reverted.
  • Test field filters, custom buttons and validation across the browsers your staff use before anything reaches production.

How we hand over

  • Deliver a written record of each script's trigger, purpose, affected DocTypes and known limits.
  • Walk administrators through how to review, enable and disable scripts, and where changes are logged.
  • Document the test cases used so your team can repeat them after an ERPNext upgrade or a browser change.

How we support

  • Offer ongoing support, upgrades and continuous testing as a retainer for scripts that need regular attention.
  • Re-test client scripts after each ERPNext minor or major release that touches the forms they change.
  • Confirm with your team which support tier, response expectations and change window apply before signing.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.