Purpose
Search the Lee County Property Appraiser site for a property using its street address and ZIP code, resolve the opaque FolioID from the search results, then open the parcel page and return visible ownership, situs, value, exemption, and tax information. Optional tax-estimator and field-card pages can provide additional tax or assessment detail after the FolioID is known.
When to Use
Use for property-tax or parcel lookups on www.leepa.org when the caller provides a street address and ZIP code. Normalize the street address to uppercase before submission; the search form accepts the address without the city when the ZIP code is supplied.
Workflow
- Navigate directly to
https://www.leepa.org/Search/PropertySearch.aspx. - Fill
input#ctl00_BodyContentPlaceHolder_WebTab1_tmpl0_AddressTextBoxwith{street-address}andinput#ctl00_BodyContentPlaceHolder_WebTab1_tmpl0_ZIPCodeTextBoxwith{zip-code}when the ZIP field is present. - Submit
input#ctl00_BodyContentPlaceHolder_WebTab1_tmpl0_SubmitPropertySearchand wait for the ASP.NET postback/navigation. If the result state has not appeared after approximately 3 seconds, submit the same control once more. - On the result page, resolve the opaque parcel identifier with this evaluator:
(() => {
const clean = (s) => (s || "").replace(/\\s+/g, " ").trim();
const candidates = [
...document.querySelectorAll('a[href*="DisplayParcel.aspx?FolioID="]'),
]
.map((a) => {
const u = new URL(a.href, location.href);
return {
text: clean(a.innerText),
url: u.href,
folioId: u.searchParams.get("FolioID"),
};
})
.filter((x) => x.folioId);
return {
candidates: [...new Map(candidates.map((x) => [x.url, x])).values()],
pageText: clean(document.body.innerText),
};
})();- Select the candidate whose displayed address, city, and ZIP best match the requested property; never guess a FolioID. Navigate directly to
https://www.leepa.org/Display/DisplayParcel.aspx?FolioID={folio-id}. - The parcel page may expose valuation details through the
a#ValuesHyperLink2tab/link. If the loaded page does not already contain the Property Values, Exemptions, TRIM, Taxing Authorities, or Solid Waste sections, click that link and wait for the tab content to load before extracting. Do not click it if the needed sections are already present. - Extract the loaded parcel page with this evaluator:
(() => {
const root =
document.querySelector("#ctl00_BodyContentPlaceHolder") || document.body;
const visible = (el) => {
const s = getComputedStyle(el);
return (
s.display !== "none" &&
s.visibility !== "hidden" &&
el.getClientRects().length > 0
);
};
const clean = (s) => (s || "").replace(/\\s+/g, " ").trim();
const tables = [...root.querySelectorAll("table")]
.filter(visible)
.map((table) =>
[...table.querySelectorAll("tr")]
.map((row) =>
[...row.querySelectorAll("th,td")].map((cell) => clean(cell.innerText)),
)
.filter((row) => row.some(Boolean)),
)
.filter((rows) => rows.length);
const fields = [
...root.querySelectorAll('label,dt,dd,[class*="label" i],[class*="value" i]'),
]
.filter(visible)
.map((el) => clean(el.innerText))
.filter(Boolean);
const sections = [...root.querySelectorAll("h1,h2,h3,h4,a,div,span")]
.filter(visible)
.map((el) => clean(el.innerText))
.filter((t) =>
/^(Property Values|Exemptions|TRIM|Taxing Authorities|Solid Waste)$/i.test(t),
);
return {
url: location.href,
folioId: new URL(location.href).searchParams.get("FolioID"),
sections: [...new Set(sections)],
text: clean(root.innerText),
fields: [...new Set(fields)],
tables,
};
})();- If additional tax detail is requested and the parcel FolioID is known, navigate directly to
https://www.leepa.org/taxestimator/default.aspx?FolioID={folio-id}and extract its visible text/tables. For field-card or construction-cost information, usehttp://fieldcards.leepa.org/CostCard/Folio/{folio-id}?TaxYear={tax-year}; substitute the requested tax year for{tax-year}. - Return the matched parcel record, including FolioID, situs address, ownership, assessed or market values, exemptions, and all tax information present in the extracted tables or visible text. Preserve multiple search candidates separately when the match is ambiguous.
Site-Specific Gotchas
- The primary property search is an ASP.NET postback form; the initial search URL generally remains
https://www.leepa.org/Search/PropertySearch.aspxand does not contain the parcel identifier. - The parcel detail page uses an opaque
FolioIDquery parameter. Always read it from a matching result link before constructing the detail URL. - The initial submit may not visibly transition to the result state. Wait about 3 seconds and submit the same button once more only if necessary.
- Use the exact generated control IDs above; do not rely on visible button text or guessed shorter IDs.
- Parcel valuation and tax sections may be behind the
ValuesHyperLink2tab/link. Reveal that content only when it is not already present, then extract the resulting page state. - Once a FolioID is resolved, the tax estimator supports the direct URL pattern
https://www.leepa.org/taxestimator/default.aspx?FolioID={folio-id}. - The field-card service supports the direct URL pattern
http://fieldcards.leepa.org/CostCard/Folio/{folio-id}?TaxYear={tax-year}for optional cost-card details. - The Lee County tax portal also supports the optional direct address-search pattern
https://lee.county-taxes.com/public/search/property_tax?search_query={url-encoded-street-address}. If it returns usable matches, extract that page directly; otherwise use the Property Appraiser flow. - The parcel page can mix tabular data with labeled sections, so retain both normalized table rows and full visible text. The CSS class-based field selectors are supplementary and may vary between page sections.
Expected Output
Return the matched property record with its parcel/folio identifier, situs address, ownership, assessed or market values, exemptions, and tax information. Include optional tax-estimator or field-card details when requested. If multiple candidates are shown, preserve each candidate separately rather than selecting by a guessed ID.