Images
Public CDN endpoints for team and region logos, cached, immutable, no auth required.
The Mr. Doge platform serves team and region logos at stable public URLs.
No API key, no auth header, no SDK call. Render them directly from <img>
or <Image> tags.
Endpoints
| Resource | URL pattern |
|---|---|
| Team logo | https://api.mrdoge.co/images/teams/<teamId>.png |
| Region flag | https://api.mrdoge.co/images/regions/<regionId>.png |
Both return 200 OK with Content-Type: image/png when the image exists.
Caching
Every response sets:
Cache-Control: public, max-age=31536000, immutableThat's one year, immutable: safe to cache aggressively on CDNs, service workers, and browser caches. The IDs are stable identifiers, so an update to a team's logo will only land when a new image is uploaded server-side (which happens infrequently and is treated as a new asset).
Use with the SDK
The Team and Region shapes returned by the SDK don't include the image
URL directly, so construct it from the id:
import { MrDoge } from "@mrdoge/node";
const mrdoge = new MrDoge({ apiKey: process.env.MRDOGE_API_KEY! });
const teams = await mrdoge.teams.list({ sports: ["soccer"], limit: 20 });
for (const team of teams) {
console.log(`https://api.mrdoge.co/images/teams/${team.id}.png`);
}A small helper keeps it tidy:
export function teamLogo(id: number) {
return `https://api.mrdoge.co/images/teams/${id}.png`;
}
export function regionFlag(id: number) {
return `https://api.mrdoge.co/images/regions/${id}.png`;
}In your app
<img
src={`https://api.mrdoge.co/images/teams/${team.id}.png`}
alt={team.name}
width={32}
height={32}
/>Plain <img> tags work everywhere. The 1-year cache header means
subsequent loads come from the browser cache.
Missing images
Not every team or region has a logo in the catalog. If the image is missing, the endpoint returns a non-200 status. Handle it with a fallback:
<img
src="https://api.mrdoge.co/images/teams/14.png"
alt="Liverpool"
onerror="this.src='/fallback-team.png'"
/>A colored circle with the team's initials is a common fallback: works without needing a generic asset:
function TeamLogo({ team }: { team: { id: number; name: string } }) {
const [failed, setFailed] = useState(false);
if (failed) {
return (
<div className="initials-circle">
{team.name.split(" ").map((w) => w[0]).join("").slice(0, 2)}
</div>
);
}
return (
<img
src={`https://api.mrdoge.co/images/teams/${team.id}.png`}
alt={team.name}
onError={() => setFailed(true)}
/>
);
}What you don't get
- No on-the-fly resizing. The endpoint serves the source PNG as-is.
For responsive sizes, run images through your own optimizer (
next/image, Cloudflare Images, imgix, etc.). - No format negotiation. PNG only. Use your image-optimization layer to convert to WebP/AVIF.
- No competition logos. Only
teamsandregionshave image endpoints. For competition branding, use the region's flag or the home team's logo as a contextual fallback. - No player headshots. Player references inside
MatchStatsare name-only, no per-player imagery.
Performance notes
- CDN-cached. Cached at the edge in front of
api.mrdoge.coand at the browser/SW layer. Cold-fetch is a single round-trip; subsequent loads come from cache. - No auth round-trip. The endpoint is excluded from API-key auth
middleware. No
Authorizationheader required. - Concurrent dedup. When many UI cards mount simultaneously and
request the same URL, both browsers and
expo-imagededupe to a single fetch.