Embedded Sponsorship SDK
This JavaScript SDK is the recommended integration approach with the Embedded Sponsorship API. It handles sponsorship status checks, button rendering, iframe lifecycle, and event communication.
SDK Versions
The SDK version is selected by the path in your script src. New integrations should
use v1, and existing v0 integrations should upgrade — see Version
History for what each version contains.
| Version | Script URL | Status |
|---|---|---|
v1 | https://api.ziprecruiter.com/ats-embed/v1/sdk.js | Current. Rolling build — picks up fixes and new features automatically. |
v0 | https://api.ziprecruiter.com/ats-embed/v0/sdk.js | Legacy, still supported. Frozen build — byte-for-byte stable (so it can be pinned with a Subresource Integrity hash), but it receives no fixes or new features. |
To upgrade from v0 to v1, change the version segment in your script src. Nothing
else in your integration changes: the SDK's JavaScript API, attributes, events, and CSS
custom properties are unchanged, and the buttons render identically unless you opt into
the ZipRecruiter logo.
The version in the SDK URL selects the SDK bundle only. Your server-side
token exchange and
sponsored status calls are unaffected and need no
change — the /ats-embed/v0/api/… paths shown throughout these docs remain supported.
The v1 SDK calls the equivalent /ats-embed/v1/api/… routes on your behalf; both
behave identically.
Because v1 is a rolling build, do not pin it with an SRI hash — the hash will break the
next time the bundle is updated. Pin SRI hashes only against v0.
If your src currently points at /ats-embed/v0.1/sdk.js, that was an interim alias
that serves the same bundle as v1. Switch it to v1; no other change is needed.
Script Tag Setup
Add the SDK script to your ATS pages:
SDK script tag
<script
src="https://api.ziprecruiter.com/ats-embed/v1/sdk.js"
data-partner-token="YOUR_ACCESS_TOKEN"
data-base-url="https://api.ziprecruiter.com"
async
></script>
Mark each job element with its external job ID:
Job element markup
<div class="job-listing" data-zr-job-id="job-001">
<h3>Senior Software Engineer</h3>
<p>San Francisco, CA</p>
</div>
The SDK scans the page for elements with data-zr-job-id attributes, injects a widget
button into each one, and keeps the buttons in sync with sponsorship state.
Attributes
SDK attributes reference
| Attribute | On | Required | Description |
|---|---|---|---|
data-partner-token | <script> | Yes | Access token from the token exchange endpoint. |
data-base-url | <script> | Yes | ZipRecruiter base URL. |
data-zr-container | <script> or any ancestor element | No | CSS selector or element that scopes the SDK's DOM scanning and MutationObserver. Defaults to document.body. Use this when your job list lives inside a specific container to avoid unnecessary DOM observation. |
data-show-logo | <script> | No | Set to "true" to prepend the ZipRecruiter logo to the sponsorship button. Off by default. v1 only — see Displaying the ZipRecruiter logo. |
data-zr-job-id | Job element | Yes (per job) | External job ID. The SDK injects a widget button into this element. |
Example with a scoped container
<script
src="https://api.ziprecruiter.com/ats-embed/v1/sdk.js"
data-partner-token="YOUR_ACCESS_TOKEN"
data-base-url="https://api.ziprecruiter.com"
data-zr-container="#job-list"
async
></script>
<div id="job-list">
<div data-zr-job-id="job-001">...</div>
<div data-zr-job-id="job-002">...</div>
</div>
Programmatic Init
If you need to initialize the SDK after page load (e.g., in a single-page app), skip the
script tag attributes and call init() directly:
Programmatic init example
ZipRecruiter.init({
partnerToken: "YOUR_ACCESS_TOKEN",
baseUrl: "https://api.ziprecruiter.com",
container: document.getElementById("job-list"), // or a CSS selector string
showLogo: true, // optional: show the ZipRecruiter logo on the button (v1 only)
});
All config properties are optional when the corresponding data-* attributes are
present on the script tag. When both are provided, the init() config takes precedence.
JavaScript API
The SDK is exposed as window.ZipRecruiter.
JavaScript API methods
| Method | Signature | Description |
|---|---|---|
init | init(config?) | Initialize the SDK. Uses script tag attributes if config is omitted. |
setPartnerToken | setPartnerToken(token) | Replace the access token without re-initializing the SDK. v1 only — see Updating the access token. |
render | render(jobId, container) | Manually render a widget for a job in a given DOM element. |
destroy | destroy(jobId) | Remove the widget for a job. |
sponsor | sponsor(jobId) | Programmatically open the sponsorship modal for a job. |
on | on(event, callback) | Subscribe to an SDK event. |
off | off(event, callback) | Unsubscribe from an SDK event. |
teardown | teardown() | Stop the SDK: disconnects the MutationObserver, destroys all widgets, and closes the modal. |
JavaScript API usage example
const onSponsored = (data) => {
console.log("Jobs sponsored:", data.jobIds);
refreshJobList();
};
ZipRecruiter.on("job:sponsored", onSponsored);
ZipRecruiter.render("job-001", document.getElementById("my-job-container"));
ZipRecruiter.sponsor("job-001");
// Later: clean up a single widget
ZipRecruiter.destroy("job-001");
// Or unsubscribe from an event
ZipRecruiter.off("job:sponsored", onSponsored);
// Or tear down everything
ZipRecruiter.teardown();
Updating the access token
An access token is issued for one email, externalEmployerId, and facilityId. If any
of these changes while the page stays loaded — for example, a single-page app switching
users, employers, or facilities — request a new token from the token
exchange on your server and pass it to the SDK:
Swap in a new access token
ZipRecruiter.setPartnerToken("NEW_ACCESS_TOKEN");
setPartnerToken closes any sponsorship modal opened under the previous token and
refreshes every button's sponsorship state under the new one. Your event subscriptions
and any widgets added with render() are kept. Passing the token the SDK already holds
does nothing. A full page load picks up the new script tag's token on its own, so no call
is needed then.
Until you swap the token, the SDK keeps acting for the previous user, employer, and facility: buttons can show the wrong sponsorship state, and anything the user does in the widget is attributed to the previous context.
setPartnerToken requires v1. The v0 bundle does not include it — see
SDK Versions. On v0, call teardown() and then init() with the new
token instead. That discards your event subscriptions and any render()ed widgets, so
register them again afterwards.
SDK Events
Subscribe with ZipRecruiter.on(event, callback) and unsubscribe with
ZipRecruiter.off(event, callback).
SDK events reference
| Event | Payload | When |
|---|---|---|
job:sponsored | { jobId, jobIds } | User completes the sponsorship flow (payment processed, jobs activated). |
job:unsponsored | { jobId } | A job's sponsorship has been stopped. |
modal:open | { jobId } | The sponsorship or manage modal opens. |
modal:close | {} | The modal closes (user closes it or a flow completes). |
Styling
SDK widget buttons are rendered inside a closed shadow DOM, so your page styles do not
affect them. To customize button appearance, set CSS custom properties on an ancestor of
the data-zr-job-id element (custom properties inherit across shadow boundaries):
CSS custom properties reference
| Property | Default | Controls |
|---|---|---|
--zr-sponsor-btn-bg | #00706C | "Sponsor" button background color. |
--zr-sponsor-btn-color | #fff | "Sponsor" button text color. |
--zr-manage-btn-bg | #9CDCD6 | "Manage" button background color. |
--zr-manage-btn-color | #1a1a1a | "Manage" button text color. |
.job-listing {
--zr-sponsor-btn-bg: #1a73e8;
--zr-sponsor-btn-color: #ffffff;
--zr-manage-btn-bg: #e8f0fe;
--zr-manage-btn-color: #1a73e8;
}
Displaying the ZipRecruiter logo
By default the sponsorship button is text only. You can prepend the ZipRecruiter logo to
the button by opting in — set data-show-logo="true" on the script tag, or pass
showLogo: true to init(). It is off by default, so leaving it unset keeps the
text-only button.
This option requires v1. The v0 bundle does not include it — see
SDK Versions.
Enable the logo via the script tag
<script
src="https://api.ziprecruiter.com/ats-embed/v1/sdk.js"
data-partner-token="YOUR_ACCESS_TOKEN"
data-base-url="https://api.ziprecruiter.com"
data-show-logo="true"
async
></script>
Enable the logo via init()
ZipRecruiter.init({
partnerToken: "YOUR_ACCESS_TOKEN",
baseUrl: "https://api.ziprecruiter.com",
showLogo: true,
});
The logo is the ZipRecruiter mark, rendered in the ZipRecruiter brand green
(#57DE70). It uses a fixed color, so it stays on-brand and is not affected by your
--zr-sponsor-btn-color / --zr-manage-btn-color customizations. You cannot substitute
your own image through this option. To use a fully custom button, render your own element
and call ZipRecruiter.sponsor(jobId) when it is clicked.
Version History
This section covers the SDK bundle only. See SDK Versions for the script URL of each version.
v1 — current
https://api.ziprecruiter.com/ats-embed/v1/sdk.js (June 2026)
v1 is a rolling build: the entries below arrived on the same URL without any change on
your side. Everything documented on this page works in v1.
Added in v1
setPartnerToken() for in-place token swaps (August 2026)
Replaces the access token without re-initializing the SDK, for pages where the user, employer, or facility changes without a page load. See Updating the access token.
Opt-in ZipRecruiter logo on the sponsorship button (July 2026)
data-show-logo="true" on the script tag, or showLogo: true in init(), prepends the
ZipRecruiter mark to the button in brand green. Off by default, so buttons are unchanged
unless you opt in. See Displaying the ZipRecruiter
logo.
Button impression and click reporting
The SDK reports two events to ZipRecruiter — one when it renders sponsorship buttons, one
when a button is clicked — so sponsorship performance can be measured end to end. This
needs no configuration and adds no partner-side work. The requests are fire-and-forget:
they never block button rendering and never surface errors on your page. No end-user or
applicant data is sent — only the job identifiers you already supply via
data-zr-job-id, the button state, and a count of buttons rendered.
Fixed in v1
render() now re-mounts a widget that was detached from the DOM
Previously, if your page rebuilt the markup around a button (for example, a single-page
app re-rendering a job list), calling render(jobId, container) again was a silent no-op
because the SDK still considered that job rendered — so the button disappeared
permanently. render() now detects the detached widget and re-mounts it. Only affects
integrations that call render() directly; script-tag auto-initialization was never
affected.
Calling init() a second time now tears down the previous instance
Previously a repeat init() — for example, to swap in a refreshed access token — left the
prior instance's DOM observer and message listener alive. That instance kept running,
which duplicated sponsored-status requests on every DOM change and fired SDK events twice
per action. The prior instance is now shut down before the new one starts.
v0 — legacy
https://api.ziprecruiter.com/ats-embed/v0/sdk.js (frozen June 2026)
The initial public SDK, frozen as a byte-stable bundle so partners who pin an SRI hash
are not broken by later releases. It remains supported, but receives no fixes or new
features — including the v1 entries above.
What v0 includes
- Automatic sponsorship button injection into every
data-zr-job-idelement, rendered in a closed shadow DOM and themeable through the CSS custom properties - Batched sponsorship status lookup, so one request covers every job on the page
- Sponsorship and manage flows in a hosted iframe modal
- The
init/render/destroy/sponsor/on/off/teardownJavaScript API and the four SDK events data-zr-containerto scope DOM scanning to a specific container- A distinct state for jobs ZipRecruiter has not ingested yet, so no button is offered for a job that cannot be sponsored
- Origin validation on all messages between the SDK and the ZipRecruiter iframe, in both directions