Ghost Kitchen & Virtual Brand Research
Pricing
from $0.075 / investigation bundle completed
Ghost Kitchen & Virtual Brand Research
Make sense of overlapping restaurant listings. Compare shared locations and conflicting details, then get a clear list of what to investigate next. Bring your own listings.
Pricing
from $0.075 / investigation bundle completed
Rating
0.0
(0)
Developer
Critical Distinction
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
15 days ago
Last modified
Categories
Share
Turn restaurant listings into your next research lead.
Bring together the listings you already have. See shared addresses, overlapping brands and conflicting observations, with the next questions in one review. A shared address is a research lead, not proof of common ownership.
Try the example · Use your listings · Pricing · Help
What you receive
| Your result | What it helps you do |
|---|---|
| Investigation queue | Decide which listings and questions to investigate first. |
| Supporting observations | Compare the facts behind a lead, including disagreements. |
| Detailed research report | Follow the supplied evidence and see what still needs checking. |
For example, two sources may describe a restaurant as delivery-only and as offering dine-in. The review brings that disagreement into view rather than quietly choosing one as the truth.
The review covers your supplied listings, not the whole market. It does not collect new listings, verify operators, inspect kitchens, or establish food quality, safety or honesty. Ordinary results are a table and JSON report, not a map, PDF or editable research workspace.
Start with your next investigation
Try the fictional restaurant example. Check the displayed price, click Start, then open Start here: Investigation queue.
You can also select Input source → Try the fictional example in the form. The built-in example uses three fictional observations and the normal $0.10 completed-analysis price at the base rate. Plan discounts may apply. It is not a free exception to the price.
Use your own listings
Choose My supplied records for direct entry or My stored data / file for a file or existing Apify Dataset. Each observation needs a business name, address and source label. Add observation dates when known.
Enter your market, appropriate data-use permission and the age after which an observation should be flagged. Use one input route; clear the previous route's data, including empty or null fields, when switching.
One run reviews 1–250 observations, which may describe fewer than 250 businesses. CSV, JSON Lines and JSON arrays are supported. A default source label can fill missing labels when the source is genuinely the same.
Use this CSV without writing JSON
Save this fictional example as first-investigation.csv:
name,address,sourceLabel,observedAt,operatingObservationAmber,10 Example Road,fictional_operator_export,2026-09-01T12:00:00Z,delivery_onlyAmber,10 Example Road,fictional_directory,2026-09-01T12:00:00Z,dine_in
Choose File upload and CSV. The headers already match. Use Exampleville (fictional), country US, permission Otherwise authorized and an observation-age limit of 30 for this sample. Adapt the context and permission for your own data.
The September 1 dates stay fixed. Later runs may flag them as old; uploading a file does not make its observations current. The result retains both conflicting observations. Save an Excel sheet as CSV before supplying it.
Pricing and useful output
$0.10 per completed analysis at the base rate, covering up to 250 supplied observations. The queue, report and this Actor's platform usage are included. You pay for a completed review, not per restaurant or positive finding. A completed inconclusive review is billable when it explains the remaining questions. This is Pay Per Event pricing.
Check current pricing and your maximum cost before running. Plan discounts may apply; subscriptions, taxes and unrelated services are separate. Apify's Try for free wording does not waive this Actor's event charge.
Invalid input and incomplete or unacknowledged result bundles do not initiate a charge. An unacknowledged charge request is different: it may already have settled. Check the run before trying again.
The queue displays up to 25 actions. The full report identifies totals and omissions for the 100-signal and 50-entity-review display limits, including conflicts outside the queue. Priority means worth investigating, not a probability or confirmed ghost-kitchen finding.
Count the opportunity, not just the listings
The optional market-count brief compares the grouping assumptions you supply. See how observations, declared brands and address units differ, and which relationships change your count most.
This reviews a supplied cohort, not the whole market. A grouping is not proof of common ownership, and a range between assumptions is not a statistical forecast. Physical-premises and operator counts remain unknown.
Open Market-count reality check in Output when using this option. The market-count settings below explain the required observation keys and groups. The ordinary investigation does not require them. There is no separate market-count charge.
Privacy, recovery and help
Use business observations you are permitted to analyze. Selected facts appear in results; choose suitable Apify access and retention settings. The Actor uses limited permissions, does not send your listings to third-party data providers or our workstation, and does not delete input or output storage.
Ask questions in the Issues tab. Include a run ID for a run problem, and use fictional examples rather than private research, credentials or access links.
A stopped run may already have results or a charge. Open Completion, charges and recovery before starting another run. An uncertain result is not proof that nothing happened. Keep your decisions in your own system; this review does not save approvals.
Compare two captures
See what changed in the restaurant listings you are researching.
Compare an earlier and a later set of supplied listings. Separate changed details, repeated observations and listings seen in only one capture, then focus your next investigation on the differences that matter.
A missing listing is not proof that a business closed. A changed name or address is a reported difference, not verified ownership, a confirmed opening or a proven relocation. The review covers your supplied records and capture scope, not the whole market.
Your usual records/source and market are the later capture. Add optional captureChanges with an earlier capture and two explicit scope/coverage declarations. Leave it absent for ordinary single-capture review. Match only original literal source IDs under explicitly stable namespaces; names, addresses and observation keys are not substitutes. If source labels change, declare namespace continuity only when known.
The fictional request below is complete. It shows changed details, an unchanged listing, one-sided observations, a duplicate receipt, conflicting identity and missing IDs. Replace its records and declarations together. Both captures may use the existing stored file/Dataset/KVS source object instead of records, with READ access. Do not use a previous report as a raw capture.
{"mode": "analyze_supplied","market": {"label": "Exampleville (fictional)","countryCode": "US"},"rightsBasis": "otherwise_authorized","freshnessHorizonDays": 30,"records": [{"name": "Amber Kitchen","address": "10 Example Road Unit B","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00017","declaredBrand": "Amber Bowl","phone": ""},{"name": "Birch Table","address": "20 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00018","category": "restaurant"},{"name": "Dawn Noodles","address": "40 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00020"},{"name": "Dawn Market","address": "41 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00020"},{"name": "Elm Pantry","address": "50 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00021"},{"name": "Unlabelled listing","address": "90 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z"}],"captureChanges": {"earlier": {"market": {"label": "Exampleville (fictional)","countryCode": "US"},"context": {"geographicScope": "Exampleville fictional municipal boundary","filterScope": "All supplied restaurant listings from the declared directory; no cuisine filter","sourceNamespaces": {"fictional-directory": "fictional-directory-stable-v1"},"coverage": "partial","capturedAt": "2026-10-02T12:00:00Z"},"records": [{"name": "Amber Kitchen","address": "10 Example Road Unit A","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00017","declaredBrand": "Amber","phone": null},{"name": "Birch Table","address": "20 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00018","category": "restaurant"},{"name": "Birch Table","address": "20 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00018","category": "restaurant"},{"name": "Cedar Lunch","address": "30 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00019"},{"name": "Dawn Noodles","address": "40 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00020"},{"name": "Dawn Market","address": "41 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z","sourceRecordId": "00020"},{"name": "Unlabelled listing","address": "90 Example Road","sourceLabel": "fictional-directory","observedAt": "2026-10-01T12:00:00Z"}]},"later": {"geographicScope": "Exampleville fictional municipal boundary","filterScope": "All supplied restaurant listings from the declared directory; no cuisine filter","sourceNamespaces": {"fictional-directory": "fictional-directory-stable-v1"},"coverage": "partial","capturedAt": "2026-10-08T12:00:00Z"}}}
Open Between-capture change brief and the complete comparison JSON, then follow its questions into the investigation queue. Before/after values distinguish missing, null, blank and conflicting nonblank evidence. No incompatible row is chosen as truth. Full original warnings and omitted-action counts remain in the detailed report. Market-count assumptions apply only to the later capture.
Coverage is your declaration: declared_complete, partial, failed or unknown. Even declared completeness establishes only absence from that supplied capture. Geographic scope, collection filters, market/country and declared namespaces must agree; narrowed filters do not establish market contraction. Optional capturedAt accepts RFC 3339 with up to nine fractional-second digits; greater precision is refused without rounding. Unknown/equal capture clocks do not establish order; future or reversed known clocks are refused. Upload and observation clocks stay separate. One capture may have an empty records array; a failed storage read is never treated as an empty capture.
Comparison is bounded to 250 observations combined, including duplicate receipts, and 8,000,000 total input/control/source bytes. Complete JSON/HTML change briefs are each limited to 512 KiB, and the full two-capture intelligence report to 8,000,000 bytes. Oversized input or output is refused, not truncated. The existing ordinary input limit is unchanged.
The optional comparison is included in the normal completed-analysis price. It adds no per-change or second-capture fee. A separate later run is another analysis. A complete review can be inconclusive and billable when it explains the remaining questions. Invalid preparation and an incomplete or unacknowledged required result bundle do not initiate the completed-analysis charge. After interruption, read Completion, charges and recovery before another run.
Advanced reference
Input and sources
The fixed mode is analyze_supplied. API requests need explicit input: {} returns a migration response rather than starting a paid example.
{"mode": "analyze_supplied","market": {"label":"Exampleville (fictional)","countryCode":"US"},"rightsBasis": "otherwise_authorized","freshnessHorizonDays": 30,"records": [{"name":"Amber","address":"10 Example Road","sourceLabel":"fictional_operator_export","observedAt":"2026-09-01T12:00:00Z","operatingObservation":"delivery_only"},{"name":"Amber","address":"10 Example Road","sourceLabel":"fictional_directory","observedAt":"2026-09-01T12:00:00Z","operatingObservation":"dine_in"}]}
rightsBasis is first_party, licensed_for_analysis or otherwise_authorized; freshnessHorizonDays is 1–3,650. Records require nonblank name, address and sourceLabel; sourceLabelDefault can fill an omitted label. Optional fields include sourceRecordId, nullable RFC 3339 observedAt, website, business phone, category, declaredBrand and operatingObservation (delivery_only or dine_in). Unknown inline fields are rejected. Observation dates cannot be in the future. Website values are credential-free absolute HTTP(S) URLs without queries or fragments.
For stored input, use source instead of records. source.type supports file, dataset or keyValueStore. File input uses the credential-free Apify KVS record URL supplied by the upload control; Dataset input uses the selected ID/name; KVS input uses an ID/name and record key. File/KVS formats are csv, jsonl or json; inference checks content type, key suffix and bounded body shape in that order.
File/KVS bodies are limited to 8,000,000 bytes. Dataset reads use at most 100 rows and 2,000,000 selected bytes per page, reading enough to detect an unacceptable 251st row. Dataset metadata is not the row-count authority. Over-limit input fails rather than truncates.
source.fieldMap selects distinct source fields for name, address, source label/record ID, observation time, website, phone, category, declared brand and operating observation. Name/address must be nonblank strings; other mapped values may be missing/null. Unmapped columns do not enter the analysis. The optional market-count observation key is read only when that feature is enabled. Source grants are READ, not WRITE. File URLs with credentials, queries or non-Apify origins are rejected.
Interpret the evidence
Different dates can represent change over time; the newer observation does not automatically win. Missing values are not contradictions. Distinct address units stay separate. Repeated or relabelled copies of one observation do not become independent corroboration.
The compatible strong_candidate label expresses investigation priority, not verified ownership or a calibrated probability. Unverified relationship signals are capped at moderate strength under rules v2. Dine-in evidence describes an operating model, not an owner. No signal is not proof of market absence.
This is an unofficial research tool. The production source card is buyer_supplied_v1. Your permission declaration covers this analysis, not independent permission to collect another provider's data. No new source feed or private/personal targeting is included.
Market-count settings
Add a unique string observationKey to each supplied row. Preserve case, spaces and leading zeros. The default source column is observationKey; source.fieldMap.observationKey can select another. Exact duplicate receipts still become aliases of one canonical observation.
marketCount needs RFC 3339 windowStart and windowEnd (start inclusive, end exclusive) and one to three hypotheses. Each hypothesis has a literal hypothesisId and groups; each group has groupId and observationKeys. For two observations, the optional object can be:
{"windowStart":"2026-10-01T00:00:00Z","windowEnd":"2026-10-02T00:00:00Z","hypotheses":[{"hypothesisId":"shared-kitchen","groups":[{"groupId":"kitchen-a","observationKeys":["0001","0002"]}]},{"hypothesisId":"separate-sites","groups":[{"groupId":"site-a","observationKeys":["0001"]},{"groupId":"site-b","observationKeys":["0002"]}]}]}
Supply matching observations separately; this object alone is not a complete request. Optional relationships declare left, right and relation (same_site or separate_sites). These are your constraints, not independently verified facts.
Each hypothesis permits up to 250 groups and 750 references; up to 500 relationships are allowed. JSON and HTML briefs are each limited to 512 KiB. Unknown keys, overlapping assignments, duplicate groups or contradictory relationships make a hypothesis unresolved, with no group count. Duplicate aliases within a group count once. Undated/outside-window observations stay separate, and unassigned observations are not silently counted as singleton sites.
Compare counts only for coherent hypotheses with the same window and mapped canonical observations. The report explains explicit merges/splits between those partitions without treating transitive similarity as identity. A historical address does not silently become a current site. Full JSON retains aliases, groups, exceptions and comparisons.
Output and interrupted work
The Dataset contains ghost-investigation-action-v1 queue rows. INTELLIGENCE_REPORT retains selected observations, duplicate receipts, entities, evidence, coverage, omissions and references. Check conflictActionCandidateCount, omittedConflictActionCount and omittedConflictEntityIds for conflicts outside the displayed queue.
OUTPUT describes the bundle before settlement; final BUNDLE_STATE is the settlement reference. A selected-input digest or storage-reference hash identifies data, not authenticity. Raw input bodies and unrelated source columns are not copied into the evidence report.
A pending bundle checkpoint is saved before publication. The same interrupted run does not blindly resubmit the bundle; a stopped worker is not reported as a completed investigation. Charging follows completed-bundle rules for investigation-bundle-completed. Inspect saved artifacts and BUNDLE_STATE after uncertain writes or charges. These operations are not one cross-storage transaction; starting a new run may repeat work and charges.
Existing saved workflows
New users can start with the example. The 0.15 family adds this guide's between-capture brief while preserving the market-count workflow and recovery handling. Use an exact numbered build for a fixed task selection. Movable tags can change. Preserve original files and read the public release notes before updating a saved workflow.
Older saved-task selectors
The following selectors preserve the October 2 recorded inventory, not a promise of current or indefinite availability. They predate the later market-count and interruption changes. Keep an existing pin until you choose to migrate, and inspect the selected build's own contract.
| Earlier family | Recorded numbered selector |
|---|---|
| 0.12 | 0.12.3 |
| 0.11 | 0.11.1 |
| 0.10 | 0.10.2 |
| 0.9 | 0.9.2 |
| 0.8 | 0.8.1 |
| 0.7 | 0.7.3 |
| 0.6 | 0.6.3 |
| 0.5 | 0.5.1 |
| 0.3 | 0.3.28 |
The public release notes summarize changes to source declarations, evidence treatment and first-use guidance. Earlier contracts do not gain current capabilities merely by appearing in this inventory. No old selector authorizes a new collection feed or unsupported data access.
