---
name: find-businesses-without-a-website
description: Produce a CSV of local businesses in one category and city that have no website, with the phone number Google Maps lists for each, using the Litescrape Google Maps and Google Search APIs. Run the numbered steps with curl or the litescrape-sdk Python package.
---

# Find local businesses without a website

Produce a CSV of businesses in one category and one city that have no website
of their own, with the phone number Google Maps lists for each.

Two endpoints do the work. Google Maps search lists the businesses. Google
Search confirms which ones have no site. Each request is one call at $0.15 per
1,000 calls.

Ask for the category and the city if either is missing. Example: "food trucks"
in "Austin, TX".

## 1. Get an API key

1. Use `LITESCRAPE_API_KEY` if it is set.
2. Otherwise send the person to https://litescrape.com/#demo for a key with 10
   free calls, and ask them to paste it. Top-ups start at $10 for 66,667 calls.
3. Send the key on every request as `Authorization: Bearer <key>`.
4. Check the balance before you start:

```bash
curl -s https://api.litescrape.com/api/keys/status \
  -H "Authorization: Bearer $LITESCRAPE_API_KEY"
```

`remaining_calls` must cover one call per Maps page plus one call per candidate
in step 4. Three pages of 20 places with a third lacking a website is about 23
calls.

## 2. List the businesses from Google Maps

One call per page of 20 places. Page with `start` in steps of 20.

```bash
curl -s "https://api.litescrape.com/api/google/maps" \
  -H "Authorization: Bearer $LITESCRAPE_API_KEY" \
  --data-urlencode "q=food trucks in Austin, TX" \
  --data-urlencode "type=search" \
  --data-urlencode "start=0" -G
```

```python
from litescrape_sdk import GoogleMaps, scrape  # pip install litescrape-sdk

pages = scrape(
    [GoogleMaps(q="food trucks in Austin, TX", type="search", start=s) for s in (0, 20, 40)],
    api_key=API_KEY,
)
places = [place for page in pages for place in page.raise_for_error().get("local_results", [])]
```

- Each item in `local_results` carries `title`, `phone`, `address`, `rating`,
  `reviews`, `type`, `place_id` and `website`.
- Keep one row per `place_id`. Maps repeats a few places across pages.
- Build the Maps link as `https://www.google.com/maps/place/?q=place_id:<place_id>`.
- Stop after the page you were asked for, after three pages if no limit was
  given, or when a page returns fewer than 20 rows.

## 3. Check the website field

A listing has its own website when `website` is present and its host is not on
this list:

```
facebook.com instagram.com linktr.ee tiktok.com x.com twitter.com youtube.com
yelp.com tripadvisor.com yellowpages.com mapquest.com bbb.org nextdoor.com
foursquare.com manta.com chamberofcommerce.com angi.com homeadvisor.com
thumbtack.com houzz.com porch.com ubereats.com doordash.com grubhub.com
favordelivery.com toasttab.com opentable.com singleplatform.com allmenus.com
menupix.com restaurantji.com eater.com wanderlog.com google.com
```

- Match the host exactly or as a subdomain: `m.facebook.com` counts as
  `facebook.com`.
- Do not match substrings: `discadatx.com` is a real website, not `x.com`.
- Drop rows that have their own website.
- Keep every other row as a candidate: the field is missing or points at a
  social page.
- This step spends no calls.

## 4. Confirm each candidate with one Google search

One call per candidate. Put the business name in quotes and add the city.
`fast_mode=true` returns organic results only.

```bash
curl -s "https://api.litescrape.com/api/google/search" \
  -H "Authorization: Bearer $LITESCRAPE_API_KEY" \
  --data-urlencode 'q="Santo Patio Taco Trailer" Austin, TX' \
  --data-urlencode "fast_mode=true" \
  --data-urlencode "gl=us" -G
```

```python
from litescrape_sdk import GoogleSearch, scrape

checks = scrape(
    [GoogleSearch(q=f'"{p["title"]}" Austin, TX', fast_mode=True, gl="us") for p in candidates],
    api_key=API_KEY,
)
```

- Read the first ten `organic_results`.
- The business has a website only when one result's `link` host is not on the
  list in step 3 and its domain name contains a distinctive word from the
  business name: four letters or longer, ignoring words such as "the", "food",
  "truck", "taco", "cafe" and the city.
- `lastrancastacostand.com` confirms "Las Trancas Taco Stand". An order page on
  `toasttab.com`, a review on `yelp.com` or an article that mentions the name
  does not.
- If no result qualifies, the business goes on the list.
- Record the reason: "no website on Maps, 9 Google results, none on the
  business's own domain" or "social page only on Maps, ...".
- Do not open the businesses' own websites or any other page.

## 5. Write the CSV

Columns, one row per business without a website:

```
name,phone,address,rating,reviews,category,maps_link,note
```

- Keep rows without a phone number and report how many rows have one.
- Report places listed, candidates checked, businesses without a website, rows
  with a phone number, calls used and the cost at $0.15 per 1,000.

## Cost, limits and stop conditions

- One call per request. A 4xx or 5xx response is refunded; retry it once after
  a short wait.
- A key runs 25 requests at a time. The SDK stays under that on its own. With
  curl, send at most 25 at once.
- Stop and report when `remaining_calls` reaches zero (HTTP 402
  `payment_required`), when a page returns fewer than 20 rows, or when you
  reach the requested number of pages. For "all" of a category, stop after
  five pages.
- Ask before spending more than 200 calls.
- Show the CSV path, the totals and the call count.

Endpoint reference: https://litescrape.com/docs. Billing rules:
https://litescrape.com/pricing.
