Search Georgia Businesses by Control Number

Site ecorp.sos.ga.govTask search-businesses-by-control-numberVersion v2Updated Sep 28, 2026Category business

Search the Georgia Secretary of State business portal using its dedicated control-number search mode and extract entity results. This skill was captured from a live agent session on ecorp.sos.ga.gov 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.

Search the Georgia Secretary of State corporation portal for business entities matching a supplied control number and return the result rows and entity links.

Use Cases

Use when the caller has a Georgia business control number and needs the corresponding entity search results or detail-page links.

Automation Flow

  1. Navigate directly to https://ecorp.sos.ga.gov/BusinessSearch.
  2. In one page evaluation, select the control-number search mode, populate input#txtControlNo with {control-number}, submit, wait for the asynchronous result update, and extract the visible table rows:
(async () => {
  const mode = document.getElementById('rdControlNo');
  const input = document.getElementById('txtControlNo');
  const button = document.getElementById('btnSearch');
  if (!mode || !input || !button) throw new Error('Control-number search controls not found');
  mode.click();
  input.value = '{control-number}';
  input.dispatchEvent(new Event('input', {bubbles: true}));
  input.dispatchEvent(new Event('change', {bubbles: true}));
  button.click();
  await new Promise(resolve => setTimeout(resolve, 5000));
  const clean = value => (value || '').replace(/\s+/g, ' ').trim();
  const visible = el => !!(el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length));
  const rows = [...document.querySelectorAll('table tr')]
    .filter(visible)
    .map(tr => {
      const cells = [...tr.querySelectorAll(':scope > th, :scope > td')].map(td => clean(td.innerText));
      const links = [...tr.querySelectorAll(':scope > th a[href], :scope > td a[href]')]
        .map(a => ({text: clean(a.innerText), href: a.href}));
      return {cells, links};
    })
    .filter(row => row.cells.length > 0 && row.cells.some(Boolean));
  const headers = rows.find(row => row.cells.every(cell => !/^\d+$/.test(cell)) && row.cells.length > 1)?.cells || [];
  const entities = rows
    .filter(row => row.links.length || row.cells.length > 1)
    .map(row => ({cells: row.cells, links: row.links}));
  return {
    url: location.href,
    controlNumber: document.getElementById('txtControlNo')?.value || null,
    headers,
    entities,
    pageText: clean(document.body.innerText).slice(0, 10000)
  };
})()

Possible Friction Points

  • The control-number mode must be selected through #rdControlNo before submitting; the associated input is #txtControlNo.
  • Submit with #btnSearch; results update asynchronously, so wait for the result table or changed page text before extracting.
  • Do not infer an entity detail URL from the control number. Use the result row's actual anchor href, because the portal may use an opaque identifier or server-generated route.
  • Result markup is table-based and may include header, informational, or mixed rows; the extractor preserves row cells and links rather than assuming a fixed column order.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=ecorp.sos.ga.gov&task=search-businesses-by-control-number