{
  "openapi": "3.0.1",
  "info": {
    "title": "TrueLocal AU Directory Listings & Reviews Scraper",
    "description": "Scrape TrueLocal.com.au business listings by keyword, location, or URL. Extract names, addresses, GPS coordinates, phones, emails, websites, ratings, and review counts. Optional review mode exports individual reviews with author, rating, text, and date. Automatic pagination included.",
    "version": "1.0",
    "x-build-id": "tUIgFUeymTHZoOpIR"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~truelocal-com-au-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-truelocal-com-au-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/abotapi~truelocal-com-au-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-truelocal-com-au-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/abotapi~truelocal-com-au-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-truelocal-com-au-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "1. Mode",
            "enum": [
              "search",
              "url",
              "reviews"
            ],
            "type": "string",
            "description": "Search = keyword + location builder (one record per listing). URL = paste TrueLocal search or profile URLs. Reviews = same inputs as Search/URL but the output is one flat record PER review.",
            "default": "search"
          },
          "searchTerms": {
            "title": "Search terms (what)",
            "type": "array",
            "description": "Keywords or categories to search, e.g. \"restaurants\", \"plumber\", \"hairdresser\". One or more.",
            "items": {
              "type": "string"
            }
          },
          "searchQueries": {
            "title": "Search queries (alias of Search terms)",
            "type": "array",
            "description": "Alias of Search terms, accepted so inputs written for other TrueLocal scrapers work unchanged. Used only when Search terms is empty.",
            "items": {
              "type": "string"
            }
          },
          "locations": {
            "title": "Locations (where)",
            "type": "array",
            "description": "Free-text locations, e.g. \"Sydney NSW\", \"Melbourne VIC\", \"Bondi Beach\". Suburb-level granularity is accepted. Enter \"Australia\" to search nationwide. A location TrueLocal does not recognise is skipped with a warning. Every keyword above is searched in every location here.",
            "items": {
              "type": "string"
            }
          },
          "urls": {
            "title": "TrueLocal URLs",
            "type": "array",
            "description": "One or more full TrueLocal URLs. Either a search URL (https://www.truelocal.com.au/search?search_terms=cafe&geo_location_terms=Sydney+NSW) which is paginated forward, a browse URL (https://www.truelocal.com.au/find/cafe/melbourne-vic) of which only the first page is read, or a profile URL (https://www.truelocal.com.au/sydney-nsw/tlp/some-listing-580000000) which is fetched directly. Multi-URL supported. Left untouched, URL mode scrapes these 3 examples; in Search and Reviews modes the untouched examples are ignored.",
            "default": [
              "https://www.truelocal.com.au/search?search_terms=cafe&geo_location_terms=Melbourne+VIC",
              "https://www.truelocal.com.au/sydney-nsw/tlp/hire-trades-581088732",
              "https://www.truelocal.com.au/find/cafe/melbourne-vic"
            ],
            "items": {
              "type": "string"
            }
          },
          "fetchDetails": {
            "title": "Fetch profile pages (richer data)",
            "type": "boolean",
            "description": "OFF by default: a run returns the lean SERP card (name, profile URL, phone, category) and is fast and cheap. Turn ON to also open each listing's profile page for full address, GPS, email, website, star rating and reviews; each listing opened adds one Profile-page enrichment event. Reviews mode and pasted profile URLs always fetch profile pages regardless of this setting.",
            "default": false
          },
          "fetchReviews": {
            "title": "Include reviews (Search/URL modes)",
            "type": "boolean",
            "description": "OFF by default. When ON, each listing record includes a nested reviews[] array. Requires Fetch profile pages, because reviews are read from that page. Reviews are read from the profile page and add no billing beyond that page's single Profile-page enrichment unit. Ignored in Reviews mode, which returns reviews as ordinary result rows.",
            "default": false
          },
          "maxReviews": {
            "title": "Max reviews per listing",
            "minimum": 0,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap the number of reviews captured per listing. Reviews add no extra billing beyond the profile-page unit. 0 = all available reviews, up to 1000. Only applies when Include reviews is ON, or in Reviews mode.",
            "default": 20
          },
          "maxPages": {
            "title": "Max pages per search",
            "minimum": 0,
            "type": "integer",
            "description": "How many SERP pages to walk per keyword/location (or per pasted search URL). Each page returns up to ~30 listings. Leave empty (or 0) to walk every result page — the walk stops naturally once a page comes back empty or repeats listings already collected, or sooner once Max listings is reached."
          },
          "maxListings": {
            "title": "Max listings (total, default 20, 0 = unlimited)",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after this many listings across all searches. In Reviews mode this caps the number of listings whose reviews are emitted. Defaults to 20 so a run stays small unless you raise it. 0 = unlimited (bounded only by the natural stop on Max pages).",
            "default": 20
          },
          "maxBusinesses": {
            "title": "Max businesses (alias of Max listings)",
            "minimum": 0,
            "type": "integer",
            "description": "Alias of Max listings. Used only when Max listings is not set."
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "TrueLocal accepts clean AU residential IPs reliably. Datacenter IPs are accepted only intermittently (the scraper rotates to recover). For consistent results use Apify residential with country AU."
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run (optional)",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by id) are skipped, so this run only saves the new ones. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead. Leave empty for a normal fresh run."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns all matching listings as NEW. Later runs compare each listing's data (name, categories, contact details, address, hours, rating, review count and reviews) with the saved copy; the scrape time, the review-returned counter, image-link hosts and the order of categories and reviews are ignored. Later runs normally return only NEW, UPDATED, and REAPPEARED listings, unchanged ones are suppressed (and not billed). Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those listings returned (and billed). State is kept separately for each mode/keyword/location/URL and detail-mode setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the mode/keyword/location/URL and detail settings, different searches then never mix state with each other."
          },
          "emitUnchanged": {
            "title": "Emit unchanged listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search in Search or URL mode, not when Max listings/Max pages capped it, not when Resume was used, and not in Reviews mode. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Field names to leave out when deciding whether a listing changed, for example ratingValue or reviewCount. Use a dotted path for nested fields, such as reviews.date. The fields stay in the output; they just never turn a listing into UPDATED. Changing this list does not mark everything as changed.",
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. Notion gets a page per item; other connectors receive a best-effort write/digest. Leave empty to skip — this never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com)."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}