Nursys Nurse License Verification (QuickConfirm)
Purpose
Verify a single U.S. nurse license on Nursys QuickConfirm (https://www.nursys.com) — the National Council of State Boards of Nursing (NCSBN) primary-source-equivalent verification database for 58 participating U.S. boards of nursing — and return the licensee's normalized record: name, license number, jurisdiction, license type (RN / PN / APRN-CNP / APRN-CRNA / APRN-CNS / APRN-CNM), compact status (single-state vs. multistate), active status, original issue date, expiration date, and discipline flag. Read-only. To "bulk-verify" an input array, the caller invokes this skill once per license; there is no batched endpoint.
When to Use
- HR / staffing teams confirming a candidate nurse's current license is in good standing in their jurisdiction.
- Credentialing services validating provider rosters against board-of-nursing data of record.
- Hospital / agency compliance teams running periodic re-checks of an active nurse roster's expiration dates and disciplinary status.
- Any flow that needs one-off (or low-volume cold) license verification against Nursys-participating boards. Use the e-Notify path instead if you already have the nurse's SSN-last-4 + birth year (see Site-Specific Gotchas) — e-Notify is captcha-free for subsequent reviews.
Workflow
Recommended method is browser with a --verified --proxies Browserbase session — but with a hard caveat. Nursys QuickConfirm requires a Google reCAPTCHA v2 image puzzle (cars / crosswalks / motorcycles / traffic-lights) to be solved per search. In 2 iterations of 2026-05-21 testing (sessions held open up to 2+ minutes each), Browserbase's --verified auto-solver did NOT clear the image puzzles before they expired (~30s server-side expiry). The form refuses to submit while the captcha is unsolved, with the visible error "Verification challenge expired. Check the checkbox again." This is the wall — see the gotcha for mitigation options.
There is no public Nursys API, no JSON endpoint, no MCP, and no CLI. NCSBN explicitly forbids "data mining or automated data gathering or extraction tools" in the terms of use (which the agent must click "I agree" on before reaching the search form). The internal ASP.NET POST endpoints (LQCSearch.aspx, LQCSummaryReport.aspx) are session-bound to the cookie set by LQCTerms.aspx accept-click plus a reCAPTCHA g-recaptcha-response token in the form payload — they cannot be hit cookieless or token-less.
Optimal browser path (per-license)
-
Spin a stealth + residential-proxy session — Imperva (the Nursys CDN) fingerprints bare sessions instantly and serves a static "additional security check is required" 403-equivalent block page with no challenge widget.
--verified --proxiesis mandatory:SID=$(browse cloud sessions create --keep-alive --verified --proxies \ | node -e "let s='';process.stdin.on('data',c=>s+=c).on('end',()=>process.stdout.write(JSON.parse(s).id))") -
Open the terms page — and expect to reload it once. First load almost always returns the Imperva block (page title is empty, the iframe shows "We are sorry, but an additional security check is required" + a User-Agent dump). Reload + wait ~10s and the second load passes — Browserbase's stealth layer needs the first round-trip to register a valid Incapsula session cookie (
visid_incap_2434260,nlbi_2434260,incap_ses_*).browse open "https://www.nursys.com/LQC/LQCTerms.aspx" --remote --session "$SID" browse wait load --remote --session "$SID" browse wait timeout 4000 --remote --session "$SID" TITLE=$(browse get title --remote --session "$SID" | grep -oE '"title": "[^"]*"' | cut -d'"' -f4) if [ -z "$TITLE" ]; then browse reload --remote --session "$SID" browse wait load --remote --session "$SID" browse wait timeout 10000 --remote --session "$SID" fi -
Dismiss the OneTrust cookie banner, then accept the FCRA terms. The banner appears as a dialog with "Accept All" + "Customize" buttons; click "Accept All" first so subsequent click-through doesn't collide with the banner overlay. Then click the "I agree" link in the terms body — this navigates to
LQCSearch.aspx. (Snapshot to find the current refs — they're regenerated each load. The literal accessibility labels arebutton: Accept Allandlink: c I agree.) -
On the search page, pick a tab. Three tabs exist:
- Search by License Number (recommended — most precise, fewest false-positives). Fields:
License number(text),License type(select:PN/RN/APRN-CNP/APRN-CRNA/APRN-CNS/APRN-CNM),State(select; see jurisdiction list below). - Search by Name (broader, partial-name matching accepted). Fields:
Last name(required, text),First name(text),License type(same select),State(same select),Search on maiden or other names(checkbox). - Search by NCSBN ID (exact match against the globally-unique NCSBN nurse ID, when the caller has one). Single text field.
Default tab is Search by Name. Click
tab: Search by License Number(ortab: Search by NCSBN ID) to switch. Note: the inner clickable that activates the tab is thetab:ref itself — do NOT click the StaticText children, which may navigate away to the e-Notify marketing page instead of switching the tab panel. - Search by License Number (recommended — most precise, fewest false-positives). Fields:
-
Fill the form. Use
browse fill(notbrowse type) for the text inputs — fill clears existing text. Usebrowse selectfor the dropdowns, passing the exact option label (e.g.RN,FLORIDA,CALIFORNIA-RN,LOUISIANA-PN). -
Solve the reCAPTCHA. Click
checkbox: I'm not a robot. An image puzzle ("Select all squares with crosswalks", etc.) will appear in a popup iframe. Browserbase's--verifiedflag may attempt to solve it but observed reliability is poor (0/3 successful solves across 2 sessions in 2026-05-21 testing — see Site-Specific Gotchas). If the agent has access to an external captcha-solving integration (2captcha, anti-captcha) or a human-in-the-loop callback, route the iframe contents to that solver. Without a working solver, the skill cannot proceed past this gate. -
Click
link: R Search(the styled "Search" button — labelledR Searchin the a11y tree because of an icon). On a successful submit, the page navigates to a results listing. Expect the URL to remain athttps://www.nursys.com/LQC/LQCSearch.aspx(it's a same-page postback with a new view); confirm by reading the breadcrumb / heading text. -
From the results page, click
View Reporton the target row. This loads the QuickConfirm License Verification Report detail view (LQCSummaryReport.aspx). -
Extract these fields from the detail report (per NCSBN's documented report schema):
- Nurse's Name
- License Jurisdiction
- License Type (one of
RN,PN,APRN-CNP,APRN-CRNA,APRN-CNS,APRN-CNM) - License Number
- Compact Status (
single state/multistate) - Is License Active (the page renders e.g.
ACTIVE/EXPIRED/INACTIVE/REVOKED/SUSPENDED) - License Original Issue Date
- License Expiration Date
- Discipline Against License (yes/no — and if yes, the historical detail block)
- Discipline Against Privilege to Practice (relevant only for compact-state multistate licenses)
- NCSBN ID (if displayed — globally-unique cross-board identifier)
-
Release the session.
browse cloud sessions update "$SID" --status REQUEST_RELEASE. Each license costs one session because the cookie session-token from Terms cannot be reused across multiple searches (page-level postback regenerates a fresh ViewState that's tied to the per-session anti-XSRF token).
Bulk-verify caller pattern
For an input array, loop and invoke per-record. Don't try to batch through a single session — Nursys page-level postbacks bind ViewState to the current selection, so submitting a second search re-uses the previous record's metadata and produces wrong results. Expect ~1 captcha challenge per record, with the captcha being the bottleneck. The skill's Zod schema:
z.object({
success: z.boolean(),
license: z.object({
licensee_name: z.string(),
license_number: z.string(),
state: z.string(),
license_type: z.enum(["RN","PN","APRN-CNP","APRN-CRNA","APRN-CNS","APRN-CNM"]),
license_type_category: z.enum(["RN","LPN","APRN"]), // PN → LPN, APRN-* → APRN
compact_status: z.enum(["single state","multistate"]).nullable(),
status: z.string(), // ACTIVE | EXPIRED | INACTIVE | REVOKED | SUSPENDED | ...
original_issue_date: z.string().nullable(), // ISO YYYY-MM-DD
expiration_date: z.string().nullable(), // ISO YYYY-MM-DD
discipline_against_license: z.boolean(),
discipline_against_privilege: z.boolean().nullable(),
ncsbn_id: z.string().nullable(),
}).nullable(),
error_reasoning: z.string().nullable(),
})
For the array case, wrap in z.array(<the schema above>).
Site-Specific Gotchas
-
Anti-bot stack is Imperva (Incapsula) + Google reCAPTCHA v2 image challenges. Both must be cleared per session. The
X-Cdn: Impervaheader is visible on every Nursys response. Without--verified --proxiesthe session fails at the Imperva pre-challenge (the static "additional security check is required" page with no interactive widget) on the very first request. Even with--verified --proxies, the first page load typically returns the Imperva block — reload once after a ~10s wait and the second load passes (Imperva needs one round-trip to register the stealth session as valid). -
THE CAPTCHA IS THE WALL. Nursys reCAPTCHA v2 image puzzles ("Select all squares with crosswalks", "Select all images with cars", "Select all squares with motorcycles" — verified across iters 2026-05-21) do not auto-solve under Browserbase
--verifiedin observed wait windows of 30s, 60s, 90s, and 120s. The widget displays "Verification challenge expired. Check the checkbox again." after ~30s of inactivity, and the parent form refuses to POST while the captcha is unsolved. NCSBN's own FAQ (ncsbn.zendesk.com/hc/.../37034543426199-Is-there-a-way-to-bypass-the-captcha) explicitly states: "NCSBN does not make any exceptions to this for Nursys QuickConfirm look-ups." For production bulk-verify, integrate a dedicated captcha-solving service (2captcha, anti-captcha, or human-in-the-loop) — the agent should extract the reCAPTCHAdata-sitekeyfromiframe[src*="recaptcha"](visible inside the form'sIframePresentational: reCAPTCHAelement) and the page URL, POST those to the solver, thenbrowse evalto inject the returnedg-recaptcha-responsetoken into the textarea#g-recaptcha-responsebefore clicking Search. Without an external solver, this skill terminates at step 6 of the workflow. -
e-Notify is the captcha-free path — but it requires PII the bulk-verify caller usually doesn't have. Per NCSBN's enrollment requirements, adding a license to an e-Notify nurse list requires (a) license number + license type + jurisdiction (or NCSBN ID), (b) last 4 digits of SSN, (c) birth year, and (d) work address. Items b–c are used at enrollment time to verify employment relationship and are never stored. Once a license is enrolled to the e-Notify nurse list, subsequent re-checks of that license — including downloading the Nursys Nurse Report — are captcha-free. Decision tree: if the caller's input rows include SSN-last-4 + birth-year per nurse, build a separate
enroll-and-verifyflow againsthttps://www.nursys.com/EN/(e-Notify); if they only have license + state + name (typical cold-verify case), QuickConfirm + captcha-solver is the only path. -
LQCSearch.aspx302-redirects back toLQCTerms.aspxif you skip the terms acceptance. TheBIGipServerpool-nursys-com+ASP.NET_SessionIdcookies are set by the GET ofLQCTerms.aspx, but the postback-token that the search page validates is only granted after the I-agree click. Deep-linking to the search URL with a fresh cookie jar 302s you back to Terms every time. Always start atLQCTerms.aspx. -
The "Search by Name" tab is the default — not "Search by License Number". The NCSBN how-to FAQ recommends the License Number tab because partial-name searches return up to dozens of homonyms (a
SMITHsearch in FLORIDA RN returns hundreds), but the UI lands on Name first. If the caller has only a name, use the Name tab +Search on maiden or other namescheckbox; if they have the number, switch tabs first. -
Tab-switching tab refs vs. their children: in the accessibility tree the tab itself (
tab: Search by License Number) is the correct click target. The nestedStaticText: Searchchildren render at higher refs but clicking them sometimes triggers a marketing-link redirect toEN/ENAbout.aspxinstead of switching the panel. Verified during iter-1: clicking the[X-2520]ref (a child of the tab) navigated away; clicking the[X-5002]ref (the tab itself) switched panels in-place. -
58 participating jurisdictions, not 50 states. The State dropdown is not a US-states list — it includes US territories (American Samoa, Guam, Northern Mariana Islands, Virgin Islands) and splits some states into board-of-nursing-level entries:
CALIFORNIA-RNvs.CALIFORNIA-VN,LOUISIANA-PNvs.LOUISIANA-RN,WEST VIRGINIA-PNvs.WEST VIRGINIA-RN. The label is the exact dropdown text — case-sensitive when passing tobrowse select. States NOT in the list are not Nursys-participating — for those, the caller must verify against the individual board's public lookup tool. As of 2026-05-21 the dropdown does NOT include Alaska's advanced practice tier (PN/RN only) and several other tiered exclusions; checkhttps://www.nursys.com/LQC/LQCJurisdictions.aspxfor the live participation grid. -
License type enum is 6 values, not 3. The task spec says "RN / LPN / APRN" but Nursys distinguishes the four APRN sub-types:
APRN-CNP(certified nurse practitioner),APRN-CRNA(certified registered nurse anesthetist),APRN-CNS(clinical nurse specialist),APRN-CNM(certified nurse-midwife).PNis Nursys's label for the LPN/LVN/VN tier. Normalize on output:PN → LPN,APRN-* → APRN, RN staysRN. Preserve the exact Nursys label inlicense_typeand the normalized category inlicense_type_category. -
Don't waste time scripting against GraphQL / JSON endpoints — there aren't any. Nursys is a classic ASP.NET WebForms application; every interaction is a server-side ViewState postback. The only "data" endpoints are the rendered
.aspxpages. The CSP allows the page to callapi.smooch.io(Zendesk chat),geolocation.onetrust.com(cookie consent),accept.authorize.net(subscription billing for e-Notify Plus), and Google Tag Manager — none of which expose license data. -
Session-token cookies don't carry across multiple searches reliably. Each search resubmission regenerates
__VIEWSTATEand__EVENTVALIDATIONtied to the previously-rendered listing. For bulk loops, the safest pattern is one Browserbase session per license — open Terms → click I agree → fill form → solve captcha → search → view report → release. Sharing a session across N records risks state-leakage between records. -
Read-only enforcement: the only "action" buttons on the detail report are
Download Report(generates a PDF),Print, andEmail. None of these are transactional but they all generate / send something — stop at the on-screen detail and extract; do NOT click Email (sends a real email to a user-supplied address), and do not click Download repeatedly (each download is logged against the session's audit trail per NCSBN's terms). -
Sessions expire at 30 minutes wall-clock (
expiresAtis+30minfrom create) and thekeepAlive: trueflag does NOT extend that — it only prevents idle-close. Budget each per-license attempt within 5 minutes wall to leave headroom for captcha retries; for bulk loops, create + release sessions rather than holding a single long-lived session.
Expected Output
Three outcome shapes the parent caller's Zod schema should branch on:
1. Successful single-record extraction
{
"success": true,
"license": {
"licensee_name": "DOE, JANE M",
"license_number": "9355105",
"state": "FLORIDA",
"license_type": "RN",
"license_type_category": "RN",
"compact_status": "multistate",
"status": "ACTIVE",
"original_issue_date": "2010-05-15",
"expiration_date": "2026-04-30",
"discipline_against_license": false,
"discipline_against_privilege": false,
"ncsbn_id": "0012345678"
},
"error_reasoning": null
}
2. License not found in selected jurisdiction
{
"success": false,
"license": null,
"error_reasoning": "No record found for license number 9999999 (RN) in FLORIDA. The license may belong to a non-Nursys-participating board, may pre-date 1985 (Nursys's earliest record cutoff), or may not yet be synced — boards push to Nursys on a 1-7 day cadence."
}
3. Anti-bot wall (captcha not solved / Imperva block persisting)
{
"success": false,
"license": null,
"error_reasoning": "Nursys QuickConfirm reCAPTCHA v2 image challenge expired before solver returned a token (waited 120s). The skill cannot complete without an external captcha-solving integration. See Site-Specific Gotchas → 'THE CAPTCHA IS THE WALL'."
}
For the bulk-verify (array) caller, return:
{
"results": [<one of the three shapes above per input row>],
"summary": {
"total": 50,
"succeeded": 12,
"not_found": 3,
"blocked_by_captcha": 35,
"blocked_by_imperva": 0
}
}