{
  "data": {
    "id": "SH8rgwf1fMdTdbNJP",
    "actId": "D0z92JrueW1JAhXKL",
    "userId": "NL4ThgItAwaoBlffQ",
    "startedAt": "2026-11-03T14:34:50.918Z",
    "finishedAt": "2026-11-03T14:35:02.118Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 11114,
      "runTimeSecs": 11.114,
      "computeUnits": 0.012348888888888888,
      "imageSizeBytes": 321488896
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "zifX0mkAFMHe8CatY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"UK Osteopath Register Scraper Input\",\n  \"description\": \"Search the General Osteopathic Council's public register by exact surname, town, postcode, practice features or registration number, or browse every practice-linked osteopath.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"mode\": {\n      \"title\": \"Mode\",\n      \"type\": \"string\",\n      \"description\": \"Choose how to query the register.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"search\",\n        \"byRegistrationNumbers\",\n        \"fullRegister\"\n      ],\n      \"enumTitles\": [\n        \"Search by surname, location or practice features\",\n        \"Look up exact GOsC registration numbers\",\n        \"Browse the full practice-linked register\"\n      ],\n      \"default\": \"search\",\n      \"prefill\": \"search\"\n    },\n    \"surname\": {\n      \"title\": \"Exact surname\",\n      \"type\": \"string\",\n      \"description\": \"Exact surname as held by the register, case-insensitive (for example Smith). Partial surnames such as Smit do not match. Combine with location or practice features to narrow results.\",\n      \"editor\": \"textfield\",\n      \"prefill\": \"Smith\"\n    },\n    \"location\": {\n      \"title\": \"Town, county, country or postcode\",\n      \"type\": \"string\",\n      \"description\": \"Exact town, county or country name, or a UK postcode/outcode such as SW1A 1AA or SW1A. Town names must match the register's own location labels.\",\n      \"editor\": \"textfield\"\n    },\n    \"radius\": {\n      \"title\": \"Distance from postcode\",\n      \"type\": \"string\",\n      \"description\": \"Radius used when location is a UK postcode or outcode. Town and county searches use the register's own boundary.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"5mi\",\n        \"10mi\",\n        \"25mi\",\n        \"50mi\"\n      ],\n      \"enumTitles\": [\n        \"Within 5 miles\",\n        \"Within 10 miles\",\n        \"Within 25 miles\",\n        \"Within 50 miles\"\n      ],\n      \"default\": \"10mi\",\n      \"prefill\": \"10mi\"\n    },\n    \"firstName\": {\n      \"title\": \"First name contains\",\n      \"type\": \"string\",\n      \"description\": \"Optional case-insensitive contains filter applied to the first-name part of the register name.\",\n      \"editor\": \"textfield\"\n    },\n    \"disabilityAccess\": {\n      \"title\": \"Requires disabled access\",\n      \"type\": \"boolean\",\n      \"description\": \"Only return osteopaths whose practice reports disabled access. Partial access counts as access, matching the register's own filter.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"homeVisit\": {\n      \"title\": \"Offers home visits\",\n      \"type\": \"boolean\",\n      \"description\": \"Only return osteopaths whose practice reports home visits.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"welshSpoken\": {\n      \"title\": \"Welsh spoken\",\n      \"type\": \"boolean\",\n      \"description\": \"Only return osteopaths whose practice reports that Welsh is spoken.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"status\": {\n      \"title\": \"Practising status\",\n      \"type\": \"string\",\n      \"description\": \"Optional exact status filter applied after each register entry is read. Leave blank for every status.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"\",\n        \"Fully Registered\",\n        \"Non Practising\",\n        \"Practising Overseas\",\n        \"Suspended\",\n        \"Conditions of Practice\",\n        \"Undertaking\"\n      ],\n      \"enumTitles\": [\n        \"Any status\",\n        \"Fully Registered\",\n        \"Non Practising\",\n        \"Practising Overseas\",\n        \"Suspended\",\n        \"Conditions of Practice\",\n        \"Undertaking\"\n      ],\n      \"default\": \"\",\n      \"prefill\": \"\"\n    },\n    \"registeredAfter\": {\n      \"title\": \"Registered on or after\",\n      \"type\": \"string\",\n      \"description\": \"Optional ISO date (YYYY-MM-DD). Only return entries whose date of registration is on or after this date.\",\n      \"editor\": \"textfield\"\n    },\n    \"registeredBefore\": {\n      \"title\": \"Registered on or before\",\n      \"type\": \"string\",\n      \"description\": \"Optional ISO date (YYYY-MM-DD). Only return entries whose date of registration is on or before this date.\",\n      \"editor\": \"textfield\"\n    },\n    \"qualificationContains\": {\n      \"title\": \"Qualification contains\",\n      \"type\": \"string\",\n      \"description\": \"Optional case-insensitive text filter over the published qualifications, for example Ost or DO.\",\n      \"editor\": \"textfield\"\n    },\n    \"registrationNumbers\": {\n      \"title\": \"GOsC registration numbers\",\n      \"type\": \"array\",\n      \"description\": \"Exact registration numbers for byRegistrationNumbers mode. Strings or integers are accepted; duplicates and leading zeros are normalised. Only the first 10,000 unique numbers are read.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"1766\"\n      ]\n    },\n    \"maxItems\": {\n      \"title\": \"Maximum osteopaths\",\n      \"type\": \"integer\",\n      \"description\": \"Hard cap on emitted osteopath records. The full practice-linked register currently holds about 5,688 unique registrants.\",\n      \"minimum\": 1,\n      \"maximum\": 10000,\n      \"default\": 50,\n      \"prefill\": 3\n    }\n  },\n  \"required\": [\n    \"mode\"\n  ]\n}",
    "readme": "# UK Osteopath Register (GOsC) Scraper\n\nCheck UK osteopaths against the **General Osteopathic Council (GOsC)** statutory public register at `osteopathy.org.uk`. The actor reads the register's own server-rendered pages without a browser, login, cookie, API key or proxy, and returns structured records for patient checks, credentialing, directories and research.\n\n## What it returns\n\nEach dataset item is one registrant:\n\n- **Identity**: `registrantId`, `registrationNumber`, `name`, `title`, `firstName`, `lastName`, `gender`\n- **Registration**: `practisingStatus`, `statusCategory`, `isPractising`, `hasConditions`, `sanction`, `dateOfRegistration`, `dateOfRegistrationRaw`\n- **Regulatory context**: `hasHearingNotes`, `hearingNotesUrl` (the GOsC hearing-decision page linked from the register entry)\n- **Education**: `qualifications`, `placeOfTraining`, `qualificationDate`, `qualificationYear`\n- **Contact**: `email`, `contactNumber`\n- **Practices**: `practices[]` with `name`, `practiceUrl`, `address`, `postcode`, `openingHours`, `email`, `phone`, `website`, `homeVisits`, `disabledAccess`, `welshSpoken`, plus optional `latitude`, `longitude`, `distanceMiles`\n- **Practice summary**: `primaryPracticeName`, `primaryPracticeTown`, `primaryPracticePostcode`, `practiceCount`, and `website` (the first available practice website, which may belong to a secondary practice)\n- **Provenance**: `sourceUrl`, `searchQuery`, `source`, `recordType`, `scrapedAt`\n\nEmpty values are omitted at every depth. Boolean practice facilities and derived status flags are retained even when false.\n\n## Three ways to query\n\n| Mode | What it does | Best for |\n|---|---|---|\n| `search` | Exact surname, exact town/county/country, postcode/outcode with radius, and practice-feature filters | Finding one person, a local cluster, or accessible/home-visit practices |\n| `byRegistrationNumbers` | Looks up exact GOsC numbers, accepts strings or integers, strips leading zeros, ignores duplicates and invalid all-zero values | Verifying a list of practitioners from a spreadsheet or CRM |\n| `fullRegister` | Pages through every practice-linked registrant in the browse, currently about 5,688 unique people across 481 pages of practice cards | Building a complete UK osteopath directory |\n\n`search` with no surname or location behaves like the old browse-all search. `fullRegister` is the explicit heavy-crawl mode and ignores surname, location and registration inputs while still honouring practice-feature and post-fetch filters.\n\n## Inputs\n\n| Field | Type | Default | Notes |\n|---|---|---|---|\n| `mode` | select | `search` | `search`, `byRegistrationNumbers` or `fullRegister` |\n| `surname` | text | – | Exact, case-insensitive surname; partial surnames do not match |\n| `location` | text | – | Exact town/county/country, or UK postcode/outcode |\n| `radius` | select | `10mi` | `5mi`, `10mi`, `25mi`, `50mi`; used for postcode/outcode searches |\n| `firstName` | text | – | Case-insensitive contains filter on the parsed first name |\n| `disabilityAccess` | boolean | `false` | Partial access counts as access, matching the register |\n| `homeVisit` | boolean | `false` | Practice reports home visits |\n| `welshSpoken` | boolean | `false` | Practice reports Welsh spoken |\n| `status` | select | any | Exact status filter: Fully Registered, Non Practising, Practising Overseas, Suspended, Conditions of Practice, Undertaking |\n| `registeredAfter` | text | – | ISO `YYYY-MM-DD`, inclusive |\n| `registeredBefore` | text | – | ISO `YYYY-MM-DD`, inclusive |\n| `qualificationContains` | text | – | Case-insensitive substring over qualifications |\n| `registrationNumbers` | array | – | Exact GOsC numbers for lookup mode |\n| `maxItems` | integer | `50` | 1–10,000 hard cap on emitted records |\n\nSaved tasks that still send `postcode`, `name`, `registrationNumber` or `radiusMiles` keep working: those legacy keys are mapped in code, not shown as inputs.\n\n## Examples\n\nFind osteopaths with a surname near a postcode:\n\n```json\n{\n  \"mode\": \"search\",\n  \"surname\": \"Smith\",\n  \"location\": \"SW1A 1AA\",\n  \"radius\": \"10mi\",\n  \"maxItems\": 25\n}\n```\n\nCheck a mixed list of registration numbers:\n\n```json\n{\n  \"mode\": \"byRegistrationNumbers\",\n  \"registrationNumbers\": [\"1766\", \"8123\", 10877, \"99999999\"],\n  \"maxItems\": 10\n}\n```\n\nFind regulatory cases:\n\n```json\n{\n  \"mode\": \"search\",\n  \"status\": \"Conditions of Practice\",\n  \"maxItems\": 50\n}\n```\n\nBuild a directory sample:\n\n```json\n{\n  \"mode\": \"fullRegister\",\n  \"disabilityAccess\": true,\n  \"maxItems\": 500\n}\n```\n\n## Statuses and regulatory flags\n\nThe register publishes six practising statuses. The actor keeps the original text in `practisingStatus` and adds a stable machine-readable layer:\n\n| Status | `statusCategory` | `isPractising` | `hasConditions` | `sanction` |\n|---|---|---|---|---|\n| Fully Registered | `practising` | true | false | – |\n| Non Practising | `nonPractising` | false | false | – |\n| Practising Overseas | `practisingOverseas` | true | false | – |\n| Suspended | `suspended` | false | false | `Suspended` |\n| Conditions of Practice | `conditions` | true | true | `Conditions of Practice` |\n| Undertaking | `undertaking` | true | true | `Undertaking` |\n\nAn unrecognised future status is preserved in `practisingStatus`, mapped to `statusCategory: other`, and logged once. Regulatory entries carry `hearingNotesUrl` and `hasHearingNotes`; the linked PDF is not parsed.\n\n## Location and distance\n\nWhen `location` is supplied in `search` mode, the actor geocodes the origin through postcodes.io (postcode, outcode, then place-name lookup). Practice postcodes are geocoded in batches of 100, cached for the run, and used to add `latitude`, `longitude`, `distanceMiles` on each practice and the lowest distance on the record. Distance is haversine miles from the origin. If geocoding fails, records are still returned without distance fields; the run never fails because of the geocoder.\n\n## How pagination works\n\nThe register shows 12 practice cards per page and states the total as `results of N`. The actor computes `ceil(N / 12)` pages, so the final unlinked page is included (the old actor missed it). It stops on `maxItems`, an empty page, a repeated page signature, no new registrant IDs, or the computed last page. It does not use the largest pagination link as the total. A full browse currently needs 481 pages; pages beyond the last repeat the last page.\n\nPractice cards can list several practitioners, so one page can yield more than 12 registrant IDs. Records are deduplicated by `registrantId`. The 5,761 browse figure is practices, not people; the current browse resolves to 5,688 unique registrant IDs.\n\n## Data quality\n\n- Placeholder practices such as `Practice Details`, `Practice Details Pending` and `Not Listed` are removed.\n- Practices are deduplicated by normalised name, address and phone, so legitimate branches at different addresses are kept.\n- Compact and oddly spaced postcodes are normalised; unparseable postcodes are omitted rather than guessed.\n- Websites gain `https://` when the source prints a bare domain; non-URL values are dropped.\n- `Not Listed`, `N/A`, punctuation-only phone numbers and other sentinels are omitted.\n\n## Limitations\n\n- The browse is practice-centric. Osteopaths with no practice listing, including some suspended registrants, do not appear in `fullRegister`; exact surname or registration lookup still finds them.\n- `status`, `firstName`, `qualificationContains`, `registeredAfter` and `registeredBefore` are post-fetch filters. A search that uses only those filters pages through the register to find matches, so it can be slow; combine them with a surname or location where possible. A status-only `Suspended` search cannot find practice-less suspended records in the browse; use a surname or registration number for those.\n- Removed or erased registrants are not returned by the public search at all.\n- The register's `robots.txt` disallows `/register-search/`. The actor uses low concurrency, polite pacing and only the pages needed for the requested records; it is intended for verification and directory use, not bulk republication.\n- Hearing-decision documents are linked, not downloaded or text-extracted.\n- Overseas practices often have no UK postcode, so distance and coordinates are omitted for them. Town and county extraction from overseas addresses is best-effort and may return a region or postal-code fragment when the source address has no clear town.\n- The full register is a large crawl: request `maxItems` deliberately and allow a generous run timeout for thousands of rows.\n\n## Performance and reliability\n\nThe actor uses HTTP/2 server-rendered requests at 1024 MB, with detail concurrency 6 and 0.2–0.4 s pacing. It retries 403/429/5xx responses with exponential backoff, skips records that cannot be parsed, and resumes safely after a platform migration without duplicate rows or overshooting `maxItems`. It needs no browser, credentials or proxy.\n\n## FAQ\n\n**Is this the official register?**\nYes. Every record comes from the General Osteopathic Council's own public register search at `osteopathy.org.uk/register-search/`, the same register patients use to verify an osteopath.\n\n**Why does a partial surname return nothing?**\nThe register's surname search is exact and case-insensitive. `Smith` matches Smith, but `Smit` does not. Use the full surname, or combine a first-name filter with location or practice features.\n\n**Why is the browse total 5,761 but the full register smaller?**\nThe published 5,761 is the number of practice cards. Each card can list several practitioners, and many practitioners appear on more than one card. Deduplicating registrant IDs gives about 5,688 unique people today.\n\n**Can it find a suspended osteopath with no practice?**\nYes, through exact surname or registration-number lookup. Such a person is absent from the practice-centric browse, so `fullRegister` cannot enumerate them.\n\n**Do I need a login, cookie, API key or proxy?**\nNo. The register is public and the actor makes anonymous requests. Nothing is stored or sent to a third party except optional postcode geocoding through postcodes.io.\n\n**What do the status flags mean?**\n`isPractising` is true for Fully Registered, Practising Overseas, Conditions of Practice and Undertaking, and false for Non Practising and Suspended. `hasConditions` is true for Conditions of Practice and Undertaking. `sanction` names the regulatory status for Suspended, Conditions of Practice and Undertaking.\n\n**Where do hearing notes come from?**\nRegulatory entries publish a `View hearing notes` link beside the status. The actor stores its absolute URL in `hearingNotesUrl`; it does not parse the linked decision document.\n\n**Why do some practices have no postcode or distance?**\nOverseas practices and some incomplete addresses do not contain a UK postcode. The actor keeps the address text and omits unparseable postcode, coordinate and distance fields rather than inventing values.\n\n**How long does a full-register run take?**\nThe register has 481 pages of practice cards and about 5,688 unique registrants. Detail enrichment is concurrency-limited and paced politely, so a complete crawl takes minutes and should be run with a deliberate `maxItems` and an adequate timeout.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "general-osteopathic-council-register-scraper",
      "title": "UK Osteopath Register (GOsC) Scraper",
      "description": "Search the General Osteopathic Council's official UK osteopath register by exact surname, town, postcode or registration number. Get practising status, regulatory notices, qualifications, every practice contact and optional distance.",
      "version": "2.0",
      "buildTag": "latest",
      "defaultRunOptions": {
        "build": "latest",
        "timeoutSecs": 3600,
        "memoryMbytes": 1024
      },
      "dockerfile": "./Dockerfile",
      "readme": "# UK Osteopath Register (GOsC) Scraper\n\nCheck UK osteopaths against the **General Osteopathic Council (GOsC)** statutory public register at `osteopathy.org.uk`. The actor reads the register's own server-rendered pages without a browser, login, cookie, API key or proxy, and returns structured records for patient checks, credentialing, directories and research.\n\n## What it returns\n\nEach dataset item is one registrant:\n\n- **Identity**: `registrantId`, `registrationNumber`, `name`, `title`, `firstName`, `lastName`, `gender`\n- **Registration**: `practisingStatus`, `statusCategory`, `isPractising`, `hasConditions`, `sanction`, `dateOfRegistration`, `dateOfRegistrationRaw`\n- **Regulatory context**: `hasHearingNotes`, `hearingNotesUrl` (the GOsC hearing-decision page linked from the register entry)\n- **Education**: `qualifications`, `placeOfTraining`, `qualificationDate`, `qualificationYear`\n- **Contact**: `email`, `contactNumber`\n- **Practices**: `practices[]` with `name`, `practiceUrl`, `address`, `postcode`, `openingHours`, `email`, `phone`, `website`, `homeVisits`, `disabledAccess`, `welshSpoken`, plus optional `latitude`, `longitude`, `distanceMiles`\n- **Practice summary**: `primaryPracticeName`, `primaryPracticeTown`, `primaryPracticePostcode`, `practiceCount`, and `website` (the first available practice website, which may belong to a secondary practice)\n- **Provenance**: `sourceUrl`, `searchQuery`, `source`, `recordType`, `scrapedAt`\n\nEmpty values are omitted at every depth. Boolean practice facilities and derived status flags are retained even when false.\n\n## Three ways to query\n\n| Mode | What it does | Best for |\n|---|---|---|\n| `search` | Exact surname, exact town/county/country, postcode/outcode with radius, and practice-feature filters | Finding one person, a local cluster, or accessible/home-visit practices |\n| `byRegistrationNumbers` | Looks up exact GOsC numbers, accepts strings or integers, strips leading zeros, ignores duplicates and invalid all-zero values | Verifying a list of practitioners from a spreadsheet or CRM |\n| `fullRegister` | Pages through every practice-linked registrant in the browse, currently about 5,688 unique people across 481 pages of practice cards | Building a complete UK osteopath directory |\n\n`search` with no surname or location behaves like the old browse-all search. `fullRegister` is the explicit heavy-crawl mode and ignores surname, location and registration inputs while still honouring practice-feature and post-fetch filters.\n\n## Inputs\n\n| Field | Type | Default | Notes |\n|---|---|---|---|\n| `mode` | select | `search` | `search`, `byRegistrationNumbers` or `fullRegister` |\n| `surname` | text | – | Exact, case-insensitive surname; partial surnames do not match |\n| `location` | text | – | Exact town/county/country, or UK postcode/outcode |\n| `radius` | select | `10mi` | `5mi`, `10mi`, `25mi`, `50mi`; used for postcode/outcode searches |\n| `firstName` | text | – | Case-insensitive contains filter on the parsed first name |\n| `disabilityAccess` | boolean | `false` | Partial access counts as access, matching the register |\n| `homeVisit` | boolean | `false` | Practice reports home visits |\n| `welshSpoken` | boolean | `false` | Practice reports Welsh spoken |\n| `status` | select | any | Exact status filter: Fully Registered, Non Practising, Practising Overseas, Suspended, Conditions of Practice, Undertaking |\n| `registeredAfter` | text | – | ISO `YYYY-MM-DD`, inclusive |\n| `registeredBefore` | text | – | ISO `YYYY-MM-DD`, inclusive |\n| `qualificationContains` | text | – | Case-insensitive substring over qualifications |\n| `registrationNumbers` | array | – | Exact GOsC numbers for lookup mode |\n| `maxItems` | integer | `50` | 1–10,000 hard cap on emitted records |\n\nSaved tasks that still send `postcode`, `name`, `registrationNumber` or `radiusMiles` keep working: those legacy keys are mapped in code, not shown as inputs.\n\n## Examples\n\nFind osteopaths with a surname near a postcode:\n\n```json\n{\n  \"mode\": \"search\",\n  \"surname\": \"Smith\",\n  \"location\": \"SW1A 1AA\",\n  \"radius\": \"10mi\",\n  \"maxItems\": 25\n}\n```\n\nCheck a mixed list of registration numbers:\n\n```json\n{\n  \"mode\": \"byRegistrationNumbers\",\n  \"registrationNumbers\": [\"1766\", \"8123\", 10877, \"99999999\"],\n  \"maxItems\": 10\n}\n```\n\nFind regulatory cases:\n\n```json\n{\n  \"mode\": \"search\",\n  \"status\": \"Conditions of Practice\",\n  \"maxItems\": 50\n}\n```\n\nBuild a directory sample:\n\n```json\n{\n  \"mode\": \"fullRegister\",\n  \"disabilityAccess\": true,\n  \"maxItems\": 500\n}\n```\n\n## Statuses and regulatory flags\n\nThe register publishes six practising statuses. The actor keeps the original text in `practisingStatus` and adds a stable machine-readable layer:\n\n| Status | `statusCategory` | `isPractising` | `hasConditions` | `sanction` |\n|---|---|---|---|---|\n| Fully Registered | `practising` | true | false | – |\n| Non Practising | `nonPractising` | false | false | – |\n| Practising Overseas | `practisingOverseas` | true | false | – |\n| Suspended | `suspended` | false | false | `Suspended` |\n| Conditions of Practice | `conditions` | true | true | `Conditions of Practice` |\n| Undertaking | `undertaking` | true | true | `Undertaking` |\n\nAn unrecognised future status is preserved in `practisingStatus`, mapped to `statusCategory: other`, and logged once. Regulatory entries carry `hearingNotesUrl` and `hasHearingNotes`; the linked PDF is not parsed.\n\n## Location and distance\n\nWhen `location` is supplied in `search` mode, the actor geocodes the origin through postcodes.io (postcode, outcode, then place-name lookup). Practice postcodes are geocoded in batches of 100, cached for the run, and used to add `latitude`, `longitude`, `distanceMiles` on each practice and the lowest distance on the record. Distance is haversine miles from the origin. If geocoding fails, records are still returned without distance fields; the run never fails because of the geocoder.\n\n## How pagination works\n\nThe register shows 12 practice cards per page and states the total as `results of N`. The actor computes `ceil(N / 12)` pages, so the final unlinked page is included (the old actor missed it). It stops on `maxItems`, an empty page, a repeated page signature, no new registrant IDs, or the computed last page. It does not use the largest pagination link as the total. A full browse currently needs 481 pages; pages beyond the last repeat the last page.\n\nPractice cards can list several practitioners, so one page can yield more than 12 registrant IDs. Records are deduplicated by `registrantId`. The 5,761 browse figure is practices, not people; the current browse resolves to 5,688 unique registrant IDs.\n\n## Data quality\n\n- Placeholder practices such as `Practice Details`, `Practice Details Pending` and `Not Listed` are removed.\n- Practices are deduplicated by normalised name, address and phone, so legitimate branches at different addresses are kept.\n- Compact and oddly spaced postcodes are normalised; unparseable postcodes are omitted rather than guessed.\n- Websites gain `https://` when the source prints a bare domain; non-URL values are dropped.\n- `Not Listed`, `N/A`, punctuation-only phone numbers and other sentinels are omitted.\n\n## Limitations\n\n- The browse is practice-centric. Osteopaths with no practice listing, including some suspended registrants, do not appear in `fullRegister`; exact surname or registration lookup still finds them.\n- `status`, `firstName`, `qualificationContains`, `registeredAfter` and `registeredBefore` are post-fetch filters. A search that uses only those filters pages through the register to find matches, so it can be slow; combine them with a surname or location where possible. A status-only `Suspended` search cannot find practice-less suspended records in the browse; use a surname or registration number for those.\n- Removed or erased registrants are not returned by the public search at all.\n- The register's `robots.txt` disallows `/register-search/`. The actor uses low concurrency, polite pacing and only the pages needed for the requested records; it is intended for verification and directory use, not bulk republication.\n- Hearing-decision documents are linked, not downloaded or text-extracted.\n- Overseas practices often have no UK postcode, so distance and coordinates are omitted for them. Town and county extraction from overseas addresses is best-effort and may return a region or postal-code fragment when the source address has no clear town.\n- The full register is a large crawl: request `maxItems` deliberately and allow a generous run timeout for thousands of rows.\n\n## Performance and reliability\n\nThe actor uses HTTP/2 server-rendered requests at 1024 MB, with detail concurrency 6 and 0.2–0.4 s pacing. It retries 403/429/5xx responses with exponential backoff, skips records that cannot be parsed, and resumes safely after a platform migration without duplicate rows or overshooting `maxItems`. It needs no browser, credentials or proxy.\n\n## FAQ\n\n**Is this the official register?**\nYes. Every record comes from the General Osteopathic Council's own public register search at `osteopathy.org.uk/register-search/`, the same register patients use to verify an osteopath.\n\n**Why does a partial surname return nothing?**\nThe register's surname search is exact and case-insensitive. `Smith` matches Smith, but `Smit` does not. Use the full surname, or combine a first-name filter with location or practice features.\n\n**Why is the browse total 5,761 but the full register smaller?**\nThe published 5,761 is the number of practice cards. Each card can list several practitioners, and many practitioners appear on more than one card. Deduplicating registrant IDs gives about 5,688 unique people today.\n\n**Can it find a suspended osteopath with no practice?**\nYes, through exact surname or registration-number lookup. Such a person is absent from the practice-centric browse, so `fullRegister` cannot enumerate them.\n\n**Do I need a login, cookie, API key or proxy?**\nNo. The register is public and the actor makes anonymous requests. Nothing is stored or sent to a third party except optional postcode geocoding through postcodes.io.\n\n**What do the status flags mean?**\n`isPractising` is true for Fully Registered, Practising Overseas, Conditions of Practice and Undertaking, and false for Non Practising and Suspended. `hasConditions` is true for Conditions of Practice and Undertaking. `sanction` names the regulatory status for Suspended, Conditions of Practice and Undertaking.\n\n**Where do hearing notes come from?**\nRegulatory entries publish a `View hearing notes` link beside the status. The actor stores its absolute URL in `hearingNotesUrl`; it does not parse the linked decision document.\n\n**Why do some practices have no postcode or distance?**\nOverseas practices and some incomplete addresses do not contain a UK postcode. The actor keeps the address text and omits unparseable postcode, coordinate and distance fields rather than inventing values.\n\n**How long does a full-register run take?**\nThe register has 481 pages of practice cards and about 5,688 unique registrants. Detail enrichment is concurrency-limited and paced politely, so a complete crawl takes minutes and should be run with a deliberate `maxItems` and an adequate timeout.\n",
      "input": {
        "title": "UK Osteopath Register Scraper Input",
        "description": "Search the General Osteopathic Council's public register by exact surname, town, postcode, practice features or registration number, or browse every practice-linked osteopath.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "mode": {
            "title": "Mode",
            "type": "string",
            "description": "Choose how to query the register.",
            "editor": "select",
            "enum": [
              "search",
              "byRegistrationNumbers",
              "fullRegister"
            ],
            "enumTitles": [
              "Search by surname, location or practice features",
              "Look up exact GOsC registration numbers",
              "Browse the full practice-linked register"
            ],
            "default": "search",
            "prefill": "search"
          },
          "surname": {
            "title": "Exact surname",
            "type": "string",
            "description": "Exact surname as held by the register, case-insensitive (for example Smith). Partial surnames such as Smit do not match. Combine with location or practice features to narrow results.",
            "editor": "textfield",
            "prefill": "Smith"
          },
          "location": {
            "title": "Town, county, country or postcode",
            "type": "string",
            "description": "Exact town, county or country name, or a UK postcode/outcode such as SW1A 1AA or SW1A. Town names must match the register's own location labels.",
            "editor": "textfield"
          },
          "radius": {
            "title": "Distance from postcode",
            "type": "string",
            "description": "Radius used when location is a UK postcode or outcode. Town and county searches use the register's own boundary.",
            "editor": "select",
            "enum": [
              "5mi",
              "10mi",
              "25mi",
              "50mi"
            ],
            "enumTitles": [
              "Within 5 miles",
              "Within 10 miles",
              "Within 25 miles",
              "Within 50 miles"
            ],
            "default": "10mi",
            "prefill": "10mi"
          },
          "firstName": {
            "title": "First name contains",
            "type": "string",
            "description": "Optional case-insensitive contains filter applied to the first-name part of the register name.",
            "editor": "textfield"
          },
          "disabilityAccess": {
            "title": "Requires disabled access",
            "type": "boolean",
            "description": "Only return osteopaths whose practice reports disabled access. Partial access counts as access, matching the register's own filter.",
            "default": false,
            "prefill": false
          },
          "homeVisit": {
            "title": "Offers home visits",
            "type": "boolean",
            "description": "Only return osteopaths whose practice reports home visits.",
            "default": false,
            "prefill": false
          },
          "welshSpoken": {
            "title": "Welsh spoken",
            "type": "boolean",
            "description": "Only return osteopaths whose practice reports that Welsh is spoken.",
            "default": false,
            "prefill": false
          },
          "status": {
            "title": "Practising status",
            "type": "string",
            "description": "Optional exact status filter applied after each register entry is read. Leave blank for every status.",
            "editor": "select",
            "enum": [
              "",
              "Fully Registered",
              "Non Practising",
              "Practising Overseas",
              "Suspended",
              "Conditions of Practice",
              "Undertaking"
            ],
            "enumTitles": [
              "Any status",
              "Fully Registered",
              "Non Practising",
              "Practising Overseas",
              "Suspended",
              "Conditions of Practice",
              "Undertaking"
            ],
            "default": "",
            "prefill": ""
          },
          "registeredAfter": {
            "title": "Registered on or after",
            "type": "string",
            "description": "Optional ISO date (YYYY-MM-DD). Only return entries whose date of registration is on or after this date.",
            "editor": "textfield"
          },
          "registeredBefore": {
            "title": "Registered on or before",
            "type": "string",
            "description": "Optional ISO date (YYYY-MM-DD). Only return entries whose date of registration is on or before this date.",
            "editor": "textfield"
          },
          "qualificationContains": {
            "title": "Qualification contains",
            "type": "string",
            "description": "Optional case-insensitive text filter over the published qualifications, for example Ost or DO.",
            "editor": "textfield"
          },
          "registrationNumbers": {
            "title": "GOsC registration numbers",
            "type": "array",
            "description": "Exact registration numbers for byRegistrationNumbers mode. Strings or integers are accepted; duplicates and leading zeros are normalised. Only the first 10,000 unique numbers are read.",
            "editor": "stringList",
            "prefill": [
              "1766"
            ]
          },
          "maxItems": {
            "title": "Maximum osteopaths",
            "type": "integer",
            "description": "Hard cap on emitted osteopath records. The full practice-linked register currently holds about 5,688 unique registrants.",
            "minimum": 1,
            "maximum": 10000,
            "default": 50,
            "prefill": 3
          }
        },
        "required": [
          "mode"
        ]
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "General Osteopathic Council Register Scraper Output",
        "description": "Osteopaths from the General Osteopathic Council public register: identity, GOsC registration number, practising status and regulatory flags, hearing-notes link, registration and qualification dates, every practice with contacts, primary-practice fields and optional distance.",
        "properties": {
          "osteopaths": {
            "type": "string",
            "title": "Osteopaths",
            "description": "Dataset containing every scraped osteopath registrant.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "overview": {
              "title": "Osteopaths",
              "transformation": {
                "fields": [
                  "name",
                  "registrationNumber",
                  "practisingStatus",
                  "statusCategory",
                  "isPractising",
                  "primaryPracticeName",
                  "distanceMiles",
                  "sourceUrl"
                ]
              },
              "display": {
                "component": "table",
                "properties": {}
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "2.0.1",
    "imageDigest": "57614837d055d09a1361510b859136986773fc67a31ebe41a5289f1ecb78d532",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "2.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.012348888888888888
    }
  }
}