Maintaining car brand assets across multiple websites
A dealer group site, a marketplace, an internal fleet tool: the same manufacturer logos, three codebases, three chances to drift. Point every site at one URL pattern instead of copying files between repositories, and turn a ticket per codebase per rebrand into no ticket at all.
One brand slug, three codebases
Change the slug once. Every surface re-renders from the same source.
Dealer group site
group.exampleAuthorised BMW retailer
New and approved used, three locations
Marketplace listing
marketplace.example2024 BMW · 12,400 miles£38,950
2023 BMW · 21,900 miles£31,200
2022 BMW · 34,100 miles£27,750
Fleet dashboard
fleet.internal.example| Vehicle | Driver | Status |
|---|---|---|
| M. Okafor | In service | |
| S. Lindqvist | Due MOT | |
| Unassigned | Available |
Leaselab: multiple platforms, 100 brands, one URL
- Company
- Leaselab
- Footprint
- Multiple platforms
- Library
- More than 100 automotive brands
- Before Motomarks
- An extensive operational cost
What the team stopped doing
- 01
Hours chasing updated brand assets
The asset behind the URL is updated; the URL does not change
- 02
Resizing logos by hand for each placement
size=andtype=are query parameters - 03
Applying one change across various systems
Every platform reads the same URL, so one update reaches all of them
“We run more than 100 brands across multiple platforms. Every copy of a logo folder was a liability: a different file name, a different crop, a different version. Pointing every codebase at one URL pattern removed a whole class of drift, along with the storage and build steps that came with it.”
What it changes for a multi-product business
- One rebrand, one change, every product
- A manufacturer refresh used to be a ticket in each repository, scheduled against each team's sprint. Now it is a line in the changelog and a cache expiry. Nobody coordinates three deploys.
- Replaces a ticket per repository per rebrand
- No package release for a logo
- A design-system package that contains files needs a version bump, release notes, and an upgrade pull request in every consumer. A package that contains a URL helper never releases because a logo changed.
- Replaces a release plus an upgrade PR per consumer
- One company in front of the customer
- The same person sees your marketplace, your dealer site, and your emails in the same week. Mismatched badges read as three companies. One URL pattern reads as one.
- Replaces a design QA sweep across products
- Asset cost attributed per product
- The usage dashboard breaks requests out by domain, so each product's share is visible rather than one team quietly carrying the whole library for everyone else.
- Replaces one team funding every product's logo work
What drifts when each site keeps its own files
- File names
- logo_bmw_final2.png in one repository, bmw-badge.svg in another. Nobody is sure which one is current.
- /img/bmw
- Sizes and padding
- One site trimmed the whitespace, another did not. Badges in a shared table sit at different visual weights.
- size=sm&aspect=square
- Rebrands
- A manufacturer refreshes its mark. The marketplace updates; the fleet tool ships the old badge for another year.
- Cache-Control: max-age=86400
- Missing variants
- The consumer site has the wordmark. The internal tool has a badge someone screenshotted in 2021.
- type=full|badge|wordmark
- Package versions
- The logo package is bumped in two of three apps. The third is pinned to a release from last spring.
- brandLogoUrl()
What copied logo folders cost across three codebases
Your numbers; change any input. First year = brands × minutes per brand + changes × codebases × hours per change. Each year after drops the one-time build. The model counts engineering time only; it leaves out CDN hosting, storage, and the cost of shipping an out-of-date mark.
Coverage where drift costs the most
Marks that changed in recent years
Integration in four steps
“The helper is the package. It has never needed a release for a logo change, because it has never contained one.”
- 01
Publish one URL helper
The helper is the whole package. No binaries, no release when a logo changes, because the package never contained the logo. Each product installs it and passes the slug it already stores.
packages/brand-logo/src/index.ts export type LogoType = "full" | "badge" | "wordmark"; export type LogoSize = "xs" | "sm" | "md" | "lg" | "xl"; export interface LogoOptions { type?: LogoType; size?: LogoSize; format?: "png" | "webp"; aspect?: "square" | "height"; } export function brandLogoUrl(slug: string, options: LogoOptions = {}) { const { type = "badge", size = "sm", format, aspect } = options; const params = new URLSearchParams({ type, size, token: process.env.NEXT_PUBLIC_MOTOMARKS_KEY!, }); if (format) params.set("format", format); if (aspect) params.set("aspect", aspect); return `https://motomarks.io/img/${slug}?${params}`; } - 02
Let each site choose a variant, not a file
The consumer site wants the full logo at hero size. The marketplace wants a badge in a listing row. The fleet tool wants a 16px wordmark in a table. They agree on the slug and disagree on parameters, which is the right place to disagree.
three repositories, one helper // dealer-group-web <img src={brandLogoUrl(slug, { type: "full", size: "lg" })} alt={`${name} logo`} /> // listings-frontend <img src={brandLogoUrl(slug, { type: "badge", size: "sm" })} alt={`${name} badge`} /> // fleet-ops-dashboard <img src={brandLogoUrl(slug, { type: "wordmark", size: "xs", aspect: "height" })} alt={`${name} wordmark`} /> - 03
Give each product a view of its own usage
The usage dashboard lists requests by domain. Browser requests are attributed from their
Refererautomatically. Server-side calls carry none, so name the product with the optional header to break them out.Create a separate key per product when you want to roll one without touching the others.
Optional request header GET https://api.motomarks.io/brands/bmw Authorization: Bearer sk_live_... X-Motomarks-Referer: fleet.internal.example - 04
Let the update arrive through the cache
When a published logo changes, every site picks it up on its next uncached request. Browsers hold the previous version for at most 24 hours. The public changelog lists brand additions, logo updates, aliases, and metadata changes, so the rebrand ticket becomes a line you read rather than a file you chase.
Response headers HTTP/1.1 200 OK Content-Type: image/webp Cache-Control: public, max-age=86400, immutable
Questions before you integrate
Do we need one API key per site?
One publishable key can serve every site, and the usage dashboard attributes browser traffic by domain. Create separate keys when you want to roll one product's key without touching the others. On Pro and Enterprise, each key can carry its own hostname allowlist.
What happens when a manufacturer changes its logo?
The published asset behind the URL is updated and the URL stays the same. Browsers and intermediate caches hold the previous image for up to 24 hours (Cache-Control: max-age=86400). The change is listed in the public changelog.
Can we keep a copy of the logos in our design system package?
Keep the URL helper in the package, not the files. Temporary caching for performance is within the fair use policy and Pro includes self-hosting and caching permission; bulk downloading the library for redistribution is not permitted. A package that contains only the helper never needs a release when a logo changes.
How do we handle a product behind a login?
Publishable keys work the same behind authentication. On the Free plan the attribution link must be on a publicly reachable page, so place it on your public marketing site. Startup and Pro remove the requirement.
Our databases hold legacy make names. How do we map them to slugs?
Pull the published list from the JSON API and match on name once, storing the slug alongside each record. Keep a small override map for names the API does not match (regional spellings, merged brands) and re-run the sync on a schedule.
Is a paid plan cheaper than the folder we already have?
The folder is free; keeping it current across several repositories is not. Startup is $228 a year billed monthly and Pro is $588. One rebrand applied in three codebases, each with its own review and deploy, is usually more than three hours of engineering time on its own. Leaselab, running more than 100 brands across multiple platforms, described the hand-maintained version as an extensive operational cost. The model on this page runs the comparison with your numbers.
One key.
Every site.
Create a free key, publish the helper, and retire the logo folders one repository at a time. The next rebrand is a changelog entry, not a sprint item.
Free includes 1,000 requests per day with an attribution link. Startup and Pro remove attribution.
More ways teams use Motomarks
Dealership website platforms
Teams building multi-rooftop dealer websites and inventory tools
Leasing and finance applications
Teams building lease and loan origination, quoting, and portfolio tools
Vehicle make selector
Developers adding a make picker to search, onboarding, or quoting flows