View a County Property Tax Lookup Form

Site county-taxes.netTask view-property-tax-lookup-formVersion v5Updated Aug 17, 2026Category government

Navigate directly to a county-taxes.net property-tax lookup page, handle its Cloudflare challenge, use address or parcel autocomplete when present, inspect or submit the rendered lookup form, and optionally open the returned tax-bill details. This skill was captured from a live agent session on county-taxes.net and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Open a county-taxes.net property-tax lookup form, confirm that the usable fields have rendered after any anti-bot challenge, perform an address or parcel lookup including autocomplete selection when required, and optionally inspect the returned tax-bill details.

Use Cases

Use when the caller needs to inspect, document, or use a county-taxes.net property-tax lookup form or view the details returned for a parcel, especially when the page is protected by Cloudflare Turnstile or requires selecting an autocomplete suggestion before displaying the property record.

Automation Flow

  1. Construct the direct page URL using https://county-taxes.net/{county-slug}/property-tax and navigate with page-load waiting. For San Francisco, use https://county-taxes.net/ca-sanfrancisco/property-tax.
  2. Allow the page to settle after navigation. If a Cloudflare challenge is present, invoke the browser's Cloudflare solver. Wait for the challenge and page content to settle; if it remains, invoke the solver in wait mode and, only if necessary, click challenge controls matching input[type='checkbox'], .cf-turnstile, #cf-turnstile, [id*='turnstile'], iframe, then wait again.
  3. Confirm that the lookup form controls are visible rather than treating a challenge page as the form. Run this self-contained evaluator on the loaded page:
(() => {
const visible = el => {
const s = getComputedStyle(el), r = el.getBoundingClientRect();
return s.display !== 'none' && s.visibility !== 'hidden' && r.width > 0 && r.height > 0;
};
const text = el => (el?.textContent || '').replace(/\s+/g, ' ').trim();
return [...document.querySelectorAll('form')].map((form, formIndex) => ({
formIndex,
action: form.action || location.href,
method: (form.method || 'get').toLowerCase(),
fields: [...form.querySelectorAll('input, select, textarea, button')]
  .filter(visible)
  .map((el, index) => {
    const id = el.id;
    const label = id ? document.querySelector(`label[for="${CSS.escape(id)}"]`) : el.closest('label');
    return {
      index,
      tag: el.tagName.toLowerCase(),
      type: el.getAttribute('type') || null,
      name: el.getAttribute('name') || null,
      id: id || null,
      role: el.getAttribute('role') || null,
      ariaLabel: el.getAttribute('aria-label') || null,
      placeholder: el.getAttribute('placeholder') || null,
      label: text(label),
      options: el.tagName === 'SELECT' ? [...el.options].map(o => ({value:o.value, text:text(o)})) : undefined
    };
  })
}));
})()
  1. For a lookup, fill the visible search control matching input[placeholder*='block-lot'], input[placeholder*='Bill'], input[type='search'], input[role='combobox'] with {property-or-parcel-query}. Wait for the suggestions to populate. This site may require choosing the suggestion rather than submitting the raw text. Inspect and select the first visible a[role='option'] whose normalized text matches or contains {property-or-parcel-query}; if several match, choose the most specific address/parcel suggestion. A visibility-aware autocomplete extractor and selector is:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const clean = el => (el?.textContent || '').replace(/\s+/g,' ').trim();
const options = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible).map((el,index)=>({index,tag:el.tagName.toLowerCase(),text:clean(el),href:el.href||null,selected:el.getAttribute('aria-selected')||null}));
const query = [...document.querySelectorAll('input[placeholder*="block-lot"], input[placeholder*="Bill"], input[type="search"], input[role="combobox"]')].find(visible)?.value || '';
const normalized = query.toLowerCase().trim();
const match = options.find(o => normalized && o.text.toLowerCase().includes(normalized)) || options[0];
if (match) {
  const el = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible)[match.index];
  el?.click();
}
return {query, options, selected: match || null};
})()
  1. Wait for the lookup response and any details panel to finish rendering. If no autocomplete option appears, submit by clicking the first visible control matching [aria-label*=search i], button[type=submit], form button; if none exists, dispatch a bubbling Enter key event on the active input.
  2. If the caller requests the tax-bill details and the returned state exposes a visible link or button whose trimmed text is exactly View, click it and wait for the details view to load. Do not guess a result URL because no stable post-lookup URL was observed. A runnable visibility-aware click helper is:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const view = [...document.querySelectorAll('a, button')].find(el => visible(el) && /^view$/i.test((el.textContent||'').replace(/\s+/g,' ').trim()));
if (!view) return {clicked:false};
view.click();
return {clicked:true,text:(view.textContent||'').replace(/\s+/g,' ').trim()};
})()
  1. Extract the currently rendered lookup/details state in one page evaluation:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const clean = v => (v||'').replace(/\s+/g,' ').trim();
const options = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible).map(el=>({text:clean(el.textContent),href:el.href||null,selected:el.getAttribute('aria-selected')||null}));
const fields = [...document.querySelectorAll('input, select, textarea')].filter(visible).map(el=>({name:el.name||null,id:el.id||null,value:el.value||'',placeholder:el.getAttribute('placeholder')||null}));
const rows = [...document.querySelectorAll('table tr, dl, .detail, [class*="detail"], [class*="tax"]')].filter(visible).map(el=>({text:clean(el.textContent),cells:[...el.querySelectorAll(':scope > th, :scope > td, :scope > dt, :scope > dd')].map(x=>clean(x.textContent)).filter(Boolean)})).filter(x=>x.text);
return {url:location.href,title:clean(document.title),fields,autocompleteOptions:options,details:rows};
})()
  1. Capture any requested screenshot only after the form is rendered, after the autocomplete result loads, or after the tax-bill details finish loading. Batch navigation, challenge handling, input, suggestion selection, optional View, extraction, and screenshot capture where the browser interface permits.

Possible Friction Points

  • The direct property-tax route is /ca-sanfrancisco/property-tax for San Francisco; county slugs use the {state}{county} pattern shown by this route.
  • The site may remain behind Cloudflare after initial navigation. Allow the solver to complete before inspecting or submitting; the challenge can require an additional wait-mode solve and interaction with a Turnstile checkbox or iframe.
  • Do not treat a challenge page as the lookup form. Confirm that property-tax form controls are visible before capturing the screenshot or running the evaluator.
  • The lookup input is exposed by a placeholder containing block-lot or Bill, or as a search input/combobox. Submission may require an explicit search/submit button, but the observed San Francisco flow requires waiting for and clicking an autocomplete option matching the entered parcel or address.
  • Returned lookup results may require an explicit View link or button before the tax-bill details are displayed. Match the visible control by text rather than assuming a result URL or opaque identifier.
  • No stable result-page URL or result-row structure was observed; the selected autocomplete result can leave the browser on the same property-tax route. Do not guess a direct post-lookup URL. Use the current-page evaluator after the response settles.
  • Raw detail selectors such as [class*="detail"] and [class*="tax"] are fallback selectors and may include container text; prefer the returned cells or confirmed labels when presenting structured tax fields.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=county-taxes.net&task=view-property-tax-lookup-form