You embed the booking form with one script tag and one <jims-customer-booking> element, then set its behaviour with a JSON settings attribute. It works on any platform that lets you add HTML: WordPress, Shopify, custom sites.
This guide covers version 1.20.3 of the form.
Quick start
Two steps: load the script once per page, then place the element where the form should appear.
- Add the script before the closing
</body>tag so it does not block page rendering.
<script type="module" crossorigin src="https://cdn.jims.net/customerbookingform/customerbookingform.js"></script>
- Place the element. With no settings it shows the full form: country, division, services, then contact details.
<jims-customer-booking></jims-customer-booking>
To configure it, pass JSON in the settings attribute. You only include the options you want to change; everything else keeps its default.
<jims-customer-booking settings='{
"divisions": { "selected": 1, "show": false },
"complete": { "redirect": "https://example.com/thank-you" }
}'></jims-customer-booking>
The script URL always serves the latest release, so you get fixes without changing your embed.
Writing the settings attribute
- Wrap the attribute in single quotes and use double quotes inside the JSON.
- Invalid JSON stops the form from rendering. Check it in a JSON validator if the form does not appear.
- An apostrophe in your own text (for example a custom heading) ends the attribute early. Write it as
'. - Objects merge with the defaults, key by key. Arrays replace the default array entirely.
- You can also set settings from JavaScript:
document.querySelector('jims-customer-booking').settings = { core: { popup: true } };
Where to find IDs
- Division IDs: Australia, New Zealand
- Service IDs: the internal division service tool
Configuration reference
Every option below is optional. Paths use dot notation: core.popup means {"core": {"popup": ...}}.
Behaviour and layout
| Setting | Type | Default | What it does |
|---|---|---|---|
core.popup | boolean | false | Shows the form as a full-screen popup instead of inline. See Display modes. |
core.work_guarantee | boolean | true | Shows the Jim’s work guarantee button and dialog. |
header.show | boolean | true | Shows the header (logo and step breadcrumbs). false gives a compact inline form. |
header.logo.url | string (URL) | Jim’s Local Expert logo | Logo image shown in the header. |
header.logo.division | number or "id:slug" | null | Uses that division’s logo instead of url. |
header.logo.show | boolean | true | false hides the logo visually but keeps it for screen readers. |
steps.showHeadings | boolean | true | Shows step headings. false keeps them for screen readers only. |
steps.showSearch | boolean | true | Shows the search box on the division and services steps. |
footer.submitText | string | Submit | Text on the final submit button. |
Country and divisions
| Setting | Type | Default | What it does |
|---|---|---|---|
country.selected | string | au | Two-letter country code, for example au, nz. |
country.show | boolean | true | Shows the country picker on the division step. Forced on when country.selected is empty. |
divisions.selected | number, string or "id:slug" | null | Pre-selects a division. |
divisions.show | boolean | true | false skips the division step. Needs divisions.selected. |
divisions.toShow | number[] | [] | Only these divisions are listed, in this order. |
fmslist | string | empty | Name of a custom FMS service list, for example MowingCustomList. Changes the divisions and services offered. |
Services
| Setting | Type | Default | What it does |
|---|---|---|---|
services.selected | number[] | [] | Pre-selects services by ID. |
services.show | boolean | not set | false skips the services step. Needs a division and services.selected. |
services.multiple | boolean | true | false lets the customer pick only one service. |
services.toHide | number[] | [] | Removes these services from the list. |
services.sort | "default", "alphabetical" or number[] | "default" | Order of ungrouped services. An array lists IDs in the order to show; others follow. |
services.groups | object[] | [] | Groups services under headings. See Divisions and services. |
services.showAllWhenGrouped | boolean or "accordion" | true | With groups, adds an “All services” group for the rest. "accordion" makes it collapsible. |
Contact details step
| Setting | Type | Default | What it does |
|---|---|---|---|
customer.showServices | boolean | true | Shows the chosen services as pills above the fields. |
customer.showFieldLabels | boolean | false | Shows labels above fields. By default only placeholders show. |
customer.fields.business_name.show | boolean | true | Shows the business name field. |
customer.fields.comments.show | boolean | true | Shows the job details field. |
customer.fields.comments.value | string | empty | Pre-fills the job details field. |
customer.fields.subscribe.show | boolean | true | Shows the special offers opt-in. |
customer.fields.<field>.label | string | see Wording | Field label. Also placeholder and error. |
First name, last name, email, phone and address are always shown and always required.
Completion
| Setting | Type | Default | What it does |
|---|---|---|---|
complete.redirect | string (URL) | empty | Sends the customer to this URL after a successful booking. Supports placeholders. |
complete.franchiseeVideo | string (YouTube embed URL) | Jim’s franchisee video | Video on the confirmation screen when a franchisee takes the job. |
complete.contractorVideo | string (YouTube embed URL) | Jim’s contractor video | Video when a contractor takes the job. |
Tracking and URL parameters
| Setting | Type | Default | What it does |
|---|---|---|---|
urlparams | string[] | [] | Allows these page URL parameters to change the form. See Display modes and behaviour. |
utm.source, utm.medium, utm.campaign, utm.content, utm.term | string | empty | UTM values sent with the booking. Page URL utm_* parameters override them. |
core.googleAPIKey | string | built in | Google Places key for address lookup. Only change if Jim’s asks you to. |
Wording
Every piece of text can be replaced. Set the key to your own text.
| Setting | Default text |
|---|---|
divisions.content.heading | Select a division |
divisions.content.search.label | Search for a division |
divisions.content.error | Please select a division |
services.content.heading | Select services |
services.content.allgroupheading | All services |
services.content.error | Please select one or more services |
customer.content.heading | Your details |
customer.content.services | Selected services |
country.content.heading | What country are you looking for work in? |
core.content.apisubmit | Submitting your request, please do not close the screen |
core.content.apierror | We’re sorry, something unexpected has happened… |
core.content.promoBanner | Request a quote today and you’re in this week’s {prize} Jim’s voucher draw… |
The promotion banner shows only for Australia and New Zealand. Set core.content.promoBanner to "" to hide it. Search result messages accept {count} and {query}.
Divisions and services
Which steps the customer sees
The form skips steps you have already answered, but only when you also hide them.
| You set | Steps shown |
|---|---|
Nothing, or divisions.show left true | Division, services, contact details |
divisions.show: false + divisions.selected | Services, contact details |
Above + services.selected + services.show: false | Contact details only |
If you pre-select a division but leave divisions.show as true, the division step still shows with that division ticked.
With divisions.show: false and a division selected, the header uses that division’s logo and the form takes on the division’s colour.
Selecting a division
divisions.selected accepts 1, "1" or "40:fire-safety". A plain ID picks the main division. Use the id:slug form to pick an alias division that shares the ID, for example Jim’s Fire Safety under ID 40. header.logo.division accepts the same forms.
Restricting the division list
divisions.toShow lists division IDs as numbers, not strings. Divisions appear in the order given; IDs that don’t exist are ignored.
{ "divisions": { "toShow": [5, 1, 53, 37, 8] } }
Service groups
Each group has a heading, a services array of IDs, an optional content HTML string shown under the heading, and an optional accordion: true to make it collapsible. Services in a group show in the order you list them. A service can appear in more than one group. Groups with no matching services are left out.
{
"divisions": { "show": false, "selected": 1 },
"services": {
"groups": [
{ "heading": "Popular", "content": "<p>Our most-booked jobs</p>", "services": [2147, 24] },
{ "heading": "Seasonal", "services": [26], "accordion": true }
],
"showAllWhenGrouped": "accordion"
}
}
Services not in any group go in a final “All services” group. Set showAllWhenGrouped to false to drop them, or "accordion" to collapse them. services.sort orders that final group and ungrouped lists only.
Upsells
Some services offer a second service from another division on an extra step (for example, service 344 offers service 2). Jim’s manages these rules; you cannot change them in settings.
Display modes and behaviour
Popup
With core.popup: true, the form stays hidden until the page URL hash is #jims. Any link to #jims opens it, and closing it removes the hash.
Place the element directly inside <body>, at the start or end, so page layout doesn’t clip it.
<body>
<a href="#jims">Get a free quote</a>
...
<jims-customer-booking settings='{"core":{"popup":true}}'></jims-customer-booking>
</body>
Use one popup booking form per page. It can share a page with a popup franchise enquiry form.
Compact inline form
For a small form in a sidebar or landing page, hide the header, headings and extras:
{
"header": { "show": false },
"core": { "work_guarantee": false },
"steps": { "showHeadings": false }
}
Redirect after booking
complete.redirect sends the customer to your page after a successful booking, instead of the confirmation screen. Failed or incomplete bookings don’t redirect.
| Placeholder | Replaced with |
|---|---|
{division_id} | Division ID, for example 1 |
{division_name} | Division name, inserted as-is (not URL-encoded) |
{service_ids} | Comma-separated service IDs |
{service_names} | Comma-separated service names |
{ "complete": { "redirect": "https://example.com/thanks?division={division_id}&services={service_ids}" } }
URL parameters
UTM parameters (utm_source, utm_medium, utm_campaign, utm_content, utm_term, or their camelCase forms) are always read from the page URL and sent with the booking.
Other parameters are ignored unless you list them in urlparams. This stops visitors changing the form from a link.
| Parameter | Sets | Example |
|---|---|---|
msg | Job details text | ?msg=Front%20lawn |
divisionId or division | divisions.selected, and hides the division step | ?divisionId=1 |
services | services.selected (comma-separated) | ?services=24,2147 |
countryCode | country.selected | ?countryCode=nz |
serviceListName | fmslist | ?serviceListName=MowingCustomList |
{ "urlparams": ["msg", "divisionId", "services"] }
An unknown country code or service list name shows an error screen.
Examples
Copy the one closest to your page and adjust the IDs.
Division website: skip straight to services
<jims-customer-booking settings='{
"divisions": { "selected": 1, "show": false }
}'></jims-customer-booking>
Service landing page: contact details only
<jims-customer-booking settings='{
"divisions": { "selected": 1, "show": false },
"services": { "selected": [24], "show": false },
"customer": { "fields": { "comments": { "value": "Lawn mowing enquiry" } } }
}'></jims-customer-booking>
New Zealand site
<jims-customer-booking settings='{
"country": { "selected": "nz", "show": false }
}'></jims-customer-booking>
Short form: fewest fields
<jims-customer-booking settings='{
"header": { "show": false },
"core": { "work_guarantee": false },
"steps": { "showHeadings": false },
"divisions": { "selected": 1, "show": false },
"services": { "selected": [24], "show": false },
"customer": { "fields": {
"comments": { "show": false },
"subscribe": { "show": false },
"business_name": { "show": false }
} }
}'></jims-customer-booking>
One service only, alphabetical list
<jims-customer-booking settings='{
"divisions": { "selected": 1, "show": false },
"services": { "multiple": false, "sort": "alphabetical" }
}'></jims-customer-booking>
Multi-division partner site
<jims-customer-booking settings='{
"divisions": { "toShow": [1, 5, 8] },
"header": { "logo": { "url": "https://example.com/partner-logo.svg" } }
}'></jims-customer-booking>
Campaign page reading the division from the link
<jims-customer-booking settings='{
"urlparams": ["divisionId", "services", "msg"],
"complete": { "redirect": "https://example.com/thanks?d={division_id}" }
}'></jims-customer-booking>
Link to it as https://example.com/quote?divisionId=1&services=24&utm_source=facebook.
Analytics events
The form pushes events to window.dataLayer, so Google Tag Manager can pick them up with a Custom Event trigger. You don’t need GTM installed for the form to work.
| Event | Fires when |
|---|---|
jcbf-step-change | The customer moves to another step |
jcbf-country-selected | The country changes |
jcbf-division-selected | The division changes |
jcbf-services-selected | The selected services change |
jcbf-address-rejected | The customer rejects the address shown on the map |
jcbf-contact-details-invalid | Submit is clicked with invalid details |
jcbf-submit | Details are sent to Jim’s. Not yet a confirmed booking. |
jcbf-submit-response | Jim’s has replied to the submission |
jcbf-submit-complete | The booking reached a franchisee or the call centre. Use this as your conversion. |
jcbf-phone-click | A phone number is clicked |
jcbf-work-guarantee-dialog-opened | The work guarantee dialog opens |
jcbf-reset | The form is reset |
The submit-response and submit-complete events include division (ID), services (IDs) and response (result code).
Styling
The form renders inside a shadow DOM, so your site’s CSS doesn’t change it and its CSS doesn’t leak into your page. Size and place it by styling the jims-customer-booking element itself. Colours come from Jim’s branding, or from the division when the division step is hidden.
Troubleshooting
| Symptom | Check |
|---|---|
| Form doesn’t appear | Script tag is on the page with type="module"; the settings JSON is valid; no unescaped apostrophe in the attribute. |
| Popup never opens | core.popup is true and your button links to #jims. |
| Division step still shows | Set divisions.show: false as well as divisions.selected. |
| Services step skipped when you wanted it | You hid divisions and pre-selected services. Add "services": {"show": true}. |
| Some services missing | They are in services.toHide, not in any group while showAllWhenGrouped is false, or not offered by that division. |
divisions.toShow shows nothing | IDs must be numbers (1), not strings ("1"). |
| URL parameter ignored | Add it to urlparams. UTM parameters need no setting. |
| Error screen on load | Check countryCode or serviceListName values. |
| Redirect doesn’t happen | The URL must be absolute (https://…). Redirect runs only after a successful booking. |
| Logo doesn’t show | header.logo.url must be a public image URL, or the division must have a logo. |
For anything else, contact the web team at Jim’s Group with the page URL.