Dealer Inspire Source
Dealer Inspire (Cars.com) builds dealer websites for several OEMs' franchise networks. The
sites do not serve their own inventory: they query one Cars Commerce search service, and that
service is what DealerInspireInventoryRawComponent reads.
| asset | dealers |
|---|---|
mercedes/mbusa/raw/dealer_inspire_dealer_listings | 151 |
stellantis/us/raw/dealer_inspire_dealer_listings | 545 |
One component, one JSON file per OEM. The component is
ai_public.components.dealer_inspire.DealerInspireInventoryRawComponent; the
file is named by the dealers_json attribute in that OEM's defs.yaml and sits beside it.
Credentials
One API key, sent as x-api-key. It is not issued to us: every Dealer Inspire site ships it in
its own page source, and the value is identical on all of them — the same key came back from
every one of 693 sites read across two franchise networks. It is a constant in
ai_public_api.dealer_providers.dealer_inspire, not an environment variable.
Nothing else is checked. The service accepts a request with no Origin, no Referer, and no
cookies, and answers the same for every dealer.
The endpoint
POST https://websites-search.api.carscommerce.inc/api/v1/listings/{ccid}/search
{
"page": 1,
"perPage": 250,
"facetFilters": {"type_slug": ["New"]},
"requestedFields": ["vin", "stock", "manufacturer_model_code", "dealer.api_id", "..."]
}
Pages number from 1. perPage above 250 is rejected with a 400; the response carries
data.total_vehicle_count and meta.pagination.total_pages.
requestedFields is not optional in practice. Omitted, the service returns a 12-field summary
with no stock number, no dates and no options. The list the component sends is derived from the
SEARCH_SERVICE_FIELD_MAP.requestedFields array the sites themselves ship, and covers
manufacturer_model_code, model_number, date_in_stock, packages, features, mechanical,
the full pricing block and extra_fields.factory_codes.
An entry may name a nested path — dealer.api_id, media.thumbnails — which prunes the response
to that sub-key. Requesting media and extra_fields whole pulls in image URL lists and the SRP
widget configuration, which are 83% of an unpruned listing and are of no use downstream; pruning
them takes a listing from roughly 25 KB to 4 KB. extra_fields.factory_codes is kept because it
carries the OEM's own factory option codes, and it is the reason extra_fields is requested at
all.
Two fields the sites request are not requested here: history_report, whose Carfax keys are all
null on new vehicles, and brochure, which was null on every listing sampled.
A sibling POST /api/v1/facets/{ccid} returns facet value counts, including the exact spelling
of every type_slug. GET on either path is a 404 — the routes are POST-only.
Dealer identifiers
ccid is the Cars Commerce id that scopes a request to a site. It is inlined in the page
source of the dealer's own site, so a plain fetch yields it:
curl -s --http2 -L --compressed -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" -H "Referer: https://www.google.com/" https://www.mbbhm.com/ | grep -o 'var SEARCH_SERVICE = {.*};'
The homepage carries the block, so sweeping a network does not need each dealer's inventory path. Space requests to a host: a sweep of 552 sites six at a time cleared 541 in six minutes, while three requests to one host four seconds apart drew the challenge.
The same block carries the API key, so a sweep that collects ccid also confirms the key has
not rotated.
domain reaches no URL, query parameter or header — the component never sends it. It is in the
file so an entry is readable and so a ccid can be traced back to the site it came from.
A ccid can serve more than one rooftop
A dealer group running one website has one ccid for the whole group, and that ccid returns
every rooftop's vehicles, distinguished only by dealer.api_id on each listing. One site
measured at 919 new vehicles spread across three rooftops.
How common this is varies by network — sampled at roughly a third of sites on one and the large majority on another — so it is the normal case to design for, not an edge case.
api_id itself is not a stable id shape. It is sometimes the OEM's own dealer code, sometimes
an MPxxxx id, and sometimes a vanity string (klementcdj, Desert215SuperStore). Where a
network issues numeric dealer codes, a large share of api_ids are literally those codes, which
is the cheapest route to attribution when it holds.
Two consequences:
- The file holds one entry per
ccid. Two dealer codes sharing a site — one redirecting to the other's domain, say — would fetch the same vehicles twice if both were listed, so only one entry is kept.load_dealer_paramsraises on a repeatedccidrather than letting that happen silently. _request_paramscarriesccid,perPage,type_slugandpage— every part of the body that varies, under the body's own key, since nothing about a body-paginated request reaches the row otherwise.pageis meaningless without theperPageit counts in, and both are component-configurable, so a row states the window it came from rather than assuming today's defaults.requestedFieldsis a module constant and is not repeated on every row.- The dealer code the file is keyed by is deliberately not recorded: it names the site queried,
and a site serves whatever rooftops its group points at it, so stamping it would assert an
ownership that does not hold. Attribute a listing to a rooftop by its own
dealer.api_id.
The website challenge
A Dealer Inspire site answers a non-browser client with a 236 KB page titled Dealer Website
in place of the real one. Sending Referer: https://www.google.com/ defeats it outright.
Nothing else does: HTTP/1.1, the inventory path instead of the homepage, a mobile Safari user agent and a Googlebot user agent were all refused on a host that answered immediately with the referer, and three passes sharing a cookie jar collected no cookies, so there is no clearance cookie to carry. It reads as a check that lets organic search traffic through.
This matters only when reading a site to capture its ccid. The component never fetches a
dealer site — it talks to the search service, which challenges nothing.
Volume
One request per 250 new vehicles per dealer, one raw row per request. A site holding several rooftops is billed to whichever dealer code the file keys it under, so request counts track sites rather than dealers.
Not every Dealer Inspire site runs this service
A site can carry Dealer Inspire markers and still serve its inventory from somewhere else — a
shared Algolia index and Motive (api.app.ridemotive.com) both appear under sites classified as
Dealer Inspire. Those are separate platforms, not variants of this one: different endpoint,
different auth, different payload. A site with no SEARCH_SERVICE block in its page source has
nothing this component can read, whatever a provider survey calls it.