Embedding the Job Board on Your Careers Page¶
| Product | Polyguard PreScreen |
| Audience | Whoever edits your careers page (web team, marketing, or your CMS agency) |
| Console | console.polyguard.ai |
| Setup time | approximately 30 minutes |
| Contact | [email protected] |
1. Overview¶
PreScreen gives you a Polyguard-hosted careers site at your own subdomain, for example https://careers.example.com. Embedding puts that same job board inside your existing careers page instead, so candidates never leave your site and your page keeps its own header, footer and styling.
You do this by replacing one <script> tag. Everything else on your page stays as it is, including the container the job board renders into.
What the candidate sees¶
The list of open roles, the role detail pages, and the application form all appear in the place your old job board occupied. When the candidate submits an application, the Polyguard Trust Check opens over the whole page, the candidate completes it on their phone, and the application is submitted to your ATS with the verification attached.
What this does not change¶
| Your ATS setup | Unchanged. Follow your ATS guide first: Greenhouse, Lever, Workable. |
| Direct applications | Candidates who apply through LinkedIn, Indeed, a referral, or your ATS's own site are still covered by the emailed Trust Check. |
| Your hosted careers site | It stays available. Embedding adds a second place the same board is served from; it does not switch the first one off. |
Do the ATS setup first
The embed renders the board your PreScreen app is already configured for. If the hosted careers site is not yet showing your live roles, fix that before embedding: the embed will show exactly the same thing.
2. Prerequisites¶
| Requirement | Details |
|---|---|
| A working PreScreen app | Your hosted careers site loads and lists your live roles |
| Your board token | The for= value Polyguard gives you. It is the same identifier your ATS uses: the Greenhouse board token, or the {site} in https://jobs.lever.co/{site} |
| Your loader URL | Polyguard gives you the full <script src> to paste. It points at your PreScreen deployment, for example https://careers.example.com/embed/embed_js |
| Edit access to the careers page | Enough to change a script tag and add a <link> to the page head |
| The exact origins of every page that will embed | Including staging and preview domains. See Section 4 |
3. Add the embed to your page¶
3a. If you embed Greenhouse today¶
A Greenhouse-embedded careers page has a container div and Greenhouse's loader script:
<div id="grnhse_app"></div>
<script src="https://boards.greenhouse.io/embed/job_board/js?for=YOUR_TOKEN"></script>
Change the src and nothing else:
<div id="grnhse_app"></div>
<script src="https://careers.example.com/embed/greenhouse_js?for=YOUR_TOKEN"></script>
The Polyguard loader looks for the same grnhse_app div and handles the same gh_jid deep-link parameter, so existing links to individual roles keep working.
3b. If you are embedding for the first time¶
Add a container div where the board should appear, then the loader script:
<div id="polyguard_jobs"></div>
<script src="https://careers.example.com/embed/embed_js?for=YOUR_TOKEN"></script>
The loader fills the first container it finds with one of these ids, in order: jobs-container, grnhse_app, polyguard_jobs. If none of them is on the page, nothing renders and no error is shown.
3c. Where to put the script tag¶
Put the script tag anywhere after the container div, or anywhere at all with defer. The loader waits for the page to finish parsing before it looks for the container, so it cannot run too early. It can run too late only if your CMS injects the container after the page has loaded, in which case load the loader after that.
The board sizes itself: it reports its height to your page as the candidate moves between the list and a role, and the frame grows and shrinks to fit. Do not set a fixed height on the container.
4. Allow your site to embed the board¶
This step is required, and the board will not render without it.
Polyguard refuses to be embedded by any site that is not on an allowlist. This is an anti-phishing control: without it, a lookalike site could frame your real job board and collect applications behind your brand.
Send Polyguard support the full origin of every page that will embed the board, and we will add them to your app. An origin is the scheme and domain with no path, always https:
https://www.example.com
https://example.com
https://staging.example.com
Three things to get right:
httpsonly. Anhttppage cannot embed the board.- A wildcard does not cover the bare domain.
https://*.example.commatcheswww.example.combut notexample.com. Send both if you use both. - Include staging, preview and agency sandbox domains if you want to test there. Preview URLs that change per deployment need the wildcard form.
You can see the current list in the Console under Settings → PreScreen → Embedding sites. Account admins can view it; only Polyguard staff can change it, and a change takes effect on your site's next deployment rather than immediately.
The symptom of a missing origin
The container stays empty and your browser's developer console shows a Content Security Policy error mentioning frame-ancestors. That is this list, not a problem with the script tag.
5. Deep links and shareable URLs¶
The board runs inside a frame, so the address bar would normally never change as the candidate browses. The loader keeps your page's URL in step, which means candidates can copy the link to a role and it opens on that role.
| Parameter | Holds | Example |
|---|---|---|
gh_jid | The role the candidate is viewing | https://www.example.com/careers?gh_jid=4001234 |
pg_f | The current search and filter state on the roles list | https://www.example.com/careers?pg_f=q%3Ddesign |
Both are read back when the page loads, so a shared or bookmarked link reopens the same view. gh_jid is the same parameter Greenhouse uses, so links you have already published, in job adverts or on social media, keep working after you swap the script.
If your page uses its own routing or rewrites the query string, make sure it preserves unknown parameters, or these links will lose the role.
6. Make the board load faster¶
Add a preconnect hint to your careers page's <head>, above the loader tag:
<link rel="preconnect" href="https://careers.example.com" crossorigin>
The loader cannot open its connection to the board until your page has parsed the script tag, run it, and added the frame. The hint starts the DNS lookup, TCP handshake and TLS negotiation earlier so they overlap the rest of your page load, typically saving one network round trip and more on mobile connections.
Use the same origin as the loader src. The crossorigin attribute is required: the board is a cross-origin document, and a preconnect without it opens a connection the frame cannot reuse.
What this does not fix
If the board sits far down the page or inside a closed tab or accordion, browsers deliberately delay rendering it until the candidate can see it. That is normal and costs nothing, but it means timing tools may report a very slow "first paint" for the board. The number is measuring how long it took the candidate to scroll, not how long the board took to load.
7. Styling¶
The board inherits the colours, fonts and logo configured for your PreScreen app in the Console under Settings → PreScreen, so it matches your hosted careers site out of the box. It deliberately drops the site header and footer, because your own page already provides them.
Two things you may want to adjust, both handled by Polyguard support:
| You want | Ask for |
|---|---|
| The frame to match your page's content width, padding, or to hide board headings your page already shows | A tenant stylesheet targeting the embed-root class |
| The roles list shown as department tabs rather than one long list | The tabbed board layout |
If your careers page has a sticky header, tell support: there is a setting on the loader URL that leaves space for it when the board scrolls a dialog into view. It is added as &offset=120 (the height of your header in pixels) on the script src.
Sending candidates to the hosted page instead¶
By default a candidate who clicks a role stays inside the frame. You can instead have each role open your Polyguard-hosted job page as a full page, which is worth doing if your careers page is narrow or heavily styled. Ask support to switch the app's embedded board role links to the hosted page. The hosted page's "All roles" link then returns the candidate to your careers page.
8. Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
| Nothing appears where the board should be | No container with a recognised id, or the script loaded before the container existed | Check the div id is jobs-container, grnhse_app or polyguard_jobs, and that the script comes after it |
The area is blank and the browser console shows a frame-ancestors error | Your page's origin is not on the allowlist | Send the exact origin to support, then redeploy; see Section 4 |
| The board renders but is cut off, or has its own scrollbar | Your page or theme sets a fixed height on the container | Remove the height; the board sizes itself |
| A role opens but the page URL never changes | Your page strips unknown query parameters | Preserve gh_jid and pg_f; see Section 5 |
| The roles shown are out of date | Boards are cached for up to an hour | Wait for the window, or ask support to clear it after a large change in your ATS |
| The Trust Check dialog opens behind your header | A sticky header without the offset setting | Ask support for the offset value; see Section 7 |
| Roles are listed but clicking one goes to your ATS's own site | Those roles are in a department PreScreen is switched off for | Intentional. Check the disabled departments for your app in the Console |
When reporting a problem to support, include the page URL, the loader src exactly as it appears in your HTML, and any errors from your browser's developer console.
9. Support¶
- Email: [email protected]
- Console: console.polyguard.ai
- ATS setup: Greenhouse, Lever, Workable
- Sending Trust Check emails from your own domain: Sending From Your Domain