Team Matching
Table of contents
- How Team Matching Works
- Custom Team Overrides
- Examples
- Custom Teams (Teams Not in Provider Data)
- Multiple Leagues
- How It Works
- Finding Team Slugs
- Docker Volume Mount
- Use Cases
- Troubleshooting
How Team Matching Works
The API uses intelligent team matching with weighted scoring to find teams flexibly. You can use team names, cities, abbreviations, or partial matches.
Matching Priority
The system checks for matches in this order (highest to lowest priority):
- Custom Aliases - User-defined nicknames from
teams.json(highest priority) - Abbreviation - Official team abbreviation (e.g.,
LAL,BOS,NYY) - Team Nickname - Team name only (e.g.,
Lakers,Celtics,Yankees) - Short Display Name - Abbreviated form (e.g.,
LA Lakers,Boston) - Full Display Name - Complete name (e.g.,
Los Angeles Lakers) - Location/City - City or location (e.g.,
Los Angeles,Boston,New York) - Partial Matches - Fuzzy matching for convenience
Examples
/nba/lakers/celtics/thumb ✓ Team nicknames
/nba/los%20angeles/boston/thumb ✓ Cities (URL encoded spaces)
/nba/LAL/BOS/thumb ✓ Official abbreviations
/nfl/chiefs/49ers/thumb ✓ Mixed formats
/ncaaf/alabama/georgia/thumb ✓ Works with NCAA too
/mls/losangelesfc/lafc/thumb ✓ Expanded location variations
/liga/atletico%20madrid/real/thumb ✓ Accents optional (Atlético works too)
/ligue1/psg/monaco/thumb ✓ Montréal or Montreal both work
League Hierarchies with Feeder Leagues
Many leagues are configured with feeder leagues that are automatically searched when a team isn’t found in the primary league. This is especially useful for:
Promotion/Relegation Systems (Soccer):
- English Premier League → EFL Championship → EFL League One → EFL League Two
- La Liga → Segunda División
- Bundesliga → 2. Bundesliga
- Serie A → Serie B
- Ligue 1 → Ligue 2
International Competitions:
- FIFA World Cup → All World Cup Qualifiers (UEFA, CONMEBOL, CONCACAF, AFC, CAF, OFC)
When you request a team that exists in a feeder league (e.g., a Championship team), the API will automatically find it even when using the top-tier league code. This works seamlessly for promoted/relegated teams.
Example:
GET /epl/leeds/burnley/thumb
Even if Leeds United is currently in the Championship, the API will find it by searching through EPL’s feeder leagues.
NCAA Women’s Sports Fallback
Women’s NCAA sports automatically fall back to men’s teams when a team is not found:
- Women’s Basketball → Men’s Basketball
- Women’s Hockey → Men’s Hockey
- Women’s Soccer → Men’s Soccer
- Women’s Lacrosse, Volleyball, Water Polo, Softball, Field Hockey → Football
This ensures maximum compatibility when teams don’t have dedicated women’s programs in ESPN’s data.
Custom Team Overrides
For cases where ESPN’s API doesn’t match common team nicknames or has incorrect data, you can define custom aliases and data overrides in a teams.json file.
Important: Your custom teams.json file is additive - it merges with the built-in team data rather than replacing it. You only need to include the specific teams you want to customize. All built-in teams and their aliases remain available.
File Structure
The teams.json file is organized by league, with each team having optional aliases and overrides:
{
"leagueKey": {
"team-slug": {
"aliases": ["nickname1", "nickname2", "..."],
"override": {
"property": "value"
}
}
}
}
Configuration Fields
League Keys
- Use lowercase league codes (e.g.,
epl,nba,nfl,mls,ncaaf) - Must match the league identifiers used in API endpoints
- See Supported Leagues for the full list
Team Slugs
Team slugs vary by provider. To find the correct slug for a team:
Method 1: Use the /raw endpoint (Recommended)
curl http://localhost:3000/laliga/celta/raw
Look at the slug field in the response. Remove the country prefix and convert underscores to hyphens:
- ESPN format:
esp.celta_vigo→ Usecelta-vigo - TheSportsDB: Uses kebab-case team name (e.g.,
manchester-united) - HockeyTech: Uses kebab-case team name (e.g.,
belleville-senators)
Method 2: Common patterns by provider
| Provider | Format | Example Input | Slug to Use |
|---|---|---|---|
| ESPN (Soccer) | Remove country prefix + underscores→hyphens | esp.celta_vigo | celta-vigo |
| ESPN (US Sports) | Lowercase with hyphens | golden-state-warriors | golden-state-warriors |
| TheSportsDB | Kebab-case team name | Manchester United | manchester-united |
| HockeyTech | Kebab-case team name | Belleville Senators | belleville-senators |
Processing rules:
- Team slug from provider is extracted (e.g.,
esp.celta_vigo) - Country prefix after the dot is removed (e.g.,
celta_vigo) - Underscores are converted to hyphens (e.g.,
celta-vigo) - This final value must match your JSON key
Aliases Array
- List of alternative names/nicknames that should match this team
- Checked first before normal matching (highest priority)
- Case-insensitive and accent-insensitive matching
- Special characters (spaces, hyphens, etc.) are normalized during matching
"atlético"will match"atletico","Atletico Madrid","atleticomadrid", etc.- Examples:
["man utd", "man u", "mufc"],["celtadevigo", "celta de vigo"]
Override Object
- Properties to merge into/replace the team data from ESPN
- Can be empty
{}if only using aliases - Supports all team data fields returned by the API
Common override properties:
| Property | Type | Example | Description |
|---|---|---|---|
abbreviation | string | "MUN" | Team abbreviation |
color | string | "#000000" | Primary team color (hex) |
alternateColor | string | "#ffffff" | Secondary team color (hex) |
logo | string | "https://..." | Primary logo URL |
logoAlt | string | "https://..." | Alternate/dark logo URL |
city | string | "Manchester" | Team city/location |
name | string | "Red Devils" | Team nickname |
fullName | string | "Manchester United" | Full team display name |
Examples
Basic Aliases with Abbreviation Override
{
"epl": {
"man-utd": {
"aliases": ["man utd", "man u", "manutd", "mufc", "manchester united"],
"override": {
"abbreviation": "MUN"
}
}
}
}
Usage:
GET /epl/man utd/chelsea/thumb ✓ Matches via alias
GET /epl/mufc/chelsea/thumb ✓ Matches via alias
GET /epl/manchester united/chelsea/thumb ✓ Matches via alias
Aliases Only (No Overrides)
{
"epl": {
"nottm-forest": {
"aliases": ["notts forest", "forest", "nffc", "nottingham forest"],
"override": {}
}
}
}
Complete Color Override
{
"mls": {
"lafc": {
"aliases": ["losangelesfc", "los angeles fc"],
"override": {
"color": "#000000",
"alternateColor": "#c7a36f"
}
}
}
}
Logo Override
{
"nba": {
"lakers": {
"aliases": ["la lakers"],
"override": {
"logo": "https://example.com/custom-lakers-logo.png",
"logoAlt": "https://example.com/custom-lakers-logo-dark.png"
}
}
}
}
Custom Teams (Teams Not in Provider Data)
For teams that don’t exist in provider data (like conference all-star teams, special events, etc.), you can define them as custom teams with the custom: true flag. Custom teams bypass provider lookups entirely and use only the data you provide.
Custom Team Structure
{
"leagueKey": {
"team-slug": {
"custom": true,
"override": {
"name": "Team Display Name",
"abbreviation": "ABC",
"color": "#000000",
"alternateColor": "#ffffff",
"logoUrl": "https://example.com/logo.png"
}
}
}
}
Required Fields for Custom Teams
When custom: true is set, the following fields are required in the override object:
name- Full team display nameabbreviation- Team abbreviation (2-4 letters)logoUrl- URL to team logo image (PNG/JPEG/GIF/WebP)
Optional fields (auto-extracted from logo if omitted):
color- Primary color (hex format) - will be auto-extracted from logoalternateColor- Secondary color (hex format) - will be auto-extracted from logo
Example: NFL Conference Teams
{
"nfl": {
"nfc": {
"custom": true,
"override": {
"abbreviation": "NFC",
"name": "National Football Conference",
"logoUrl": "https://a.espncdn.com/i/teamlogos/nfl/500/scoreboard/nfc.png",
"color": "#013369",
"alternateColor": "#D50A0A"
}
},
"afc": {
"custom": true,
"override": {
"abbreviation": "AFC",
"name": "American Football Conference",
"logoUrl": "https://a.espncdn.com/i/teamlogos/nfl/500/scoreboard/afc.png",
"color": "#D50A0A",
"alternateColor": "#013369"
}
}
}
}
Usage:
GET
### Example: Custom Team with Auto-Extracted Colors
If you omit colors, they will be automatically extracted from the logo:
```json
{
"nfl": {
"probowl": {
"custom": true,
"override": {
"abbreviation": "PRO",
"name": "Pro Bowl",
"logoUrl": "https://example.com/probowl-logo.png"
}
}
}
}
Colors will be extracted from the logo on first use and cached for subsequent requests. /nfl/nfc/afc/thumb ✓ Custom teams GET /nfl/nfc/cowboys/thumb ✓ Custom + real team
### When to Use Custom Teams
Custom teams are ideal for:
- **Conference/Division Teams** - NFC vs AFC, Eastern Conference vs Western Conference
- **All-Star Teams** - Pro Bowl rosters, All-Star game participants
- **Special Events** - Exhibition games, charity matches
- **Historical Teams** - Defunct teams not in current data
- **Fantasy/Custom Leagues** - User-created teams for fantasy leagues
### How Custom Teams Work
1. **No Provider Lookup**: Custom teams are resolved directly from `teams.json` without querying external providers
2. **Fallback Support**: Custom teams work in the fallback chain (with `?fallback=true`)
3. **Alias Support**: You can still add aliases to custom teams for easier matching
4. **Priority**: Custom teams are checked **before** provider lookups, ensuring instant resolution
### Custom Teams with Aliases
```json
{
"nfl": {
"nfc": {
"custom": true,
"aliases": ["national football conference", "national conference"],
"override": {
"abbreviation": "NFC",
"name": "National Football Conference",
"logoUrl": "https://a.espncdn.com/i/teamlogos/nfl/500/scoreboard/nfc.png",
"color": "#013369",
"alternateColor": "#D50A0A"
}
}
}
}
Multiple Leagues
{
"epl": {
"man-utd": {
"aliases": ["man utd", "man u", "mufc"],
"override": {
"abbreviation": "MUN"
}
},
"tottenham": {
"aliases": ["spurs", "thfc", "tottenham hotspur"],
"override": {}
}
},
"nba": {
"lakers": {
"aliases": ["la lakers", "lake show"],
"override": {}
}
}
}
How It Works
- Custom Team Check (highest priority): If a team is marked with
custom: true, it’s resolved immediately fromteams.jsonwithout provider lookup - Alias Matching: When resolving a team, the system checks if the input matches any custom alias in
teams.json - ESPN Matching: If no custom team or alias matches, the system uses ESPN’s team data with intelligent fuzzy matching
- Override Application: After finding a match, any properties in the
overrideobject are merged into the final team data
Finding Team Slugs
To determine the correct slug for a team:
- Use the raw data endpoint:
GET /:league/:team/raw - Look for the
slugfield in the response - Remove the league prefix if present (e.g.,
eng.man_united→man-united,usa.lafc→lafc) - Replace underscores with hyphens
Example
curl http://localhost:3000/mls/lafc/raw
Response:
{
"id": "18966",
"slug": "usa.lafc",
"city": "LAFC",
"name": "LAFC",
...
}
Use in teams.json: "lafc" (remove usa. prefix)
Docker Volume Mount
To use a custom teams.json file with Docker:
docker run -p 3000:3000 \
-v /path/to/your/teams.json:/app/teams.json:ro \
ghcr.io/sethwv/game-thumbs:latest
Replace /path/to/your/teams.json with the absolute path to your custom file. The :ro flag makes it read-only.
Additive Merging: Your custom file is merged with the built-in team data at runtime:
- Built-in teams remain available
- Your custom teams are added to the system
- For teams that exist in both files, aliases are combined (duplicates removed)
- Your override values take precedence
- No need to maintain a complete copy of all teams
The file is loaded on server startup. Restart the container to reload changes. Check logs for merge confirmation messages.
Use Cases
Add Common Nicknames
ESPN doesn’t recognize all common team nicknames:
{
"epl": {
"man-utd": {
"aliases": ["man utd", "man u", "mufc"],
"override": {}
},
"tottenham": {
"aliases": ["spurs", "thfc"],
"override": {}
}
}
}
Fix Incorrect Abbreviations
Some teams have inconsistent abbreviations in ESPN’s data:
{
"epl": {
"man-utd": {
"aliases": [],
"override": {
"abbreviation": "MUN"
}
}
}
}
Override Team Colors
ESPN’s color data is sometimes missing or incorrect:
{
"nba": {
"heat": {
"aliases": [],
"override": {
"color": "#98002E",
"alternateColor": "#F9A01B"
}
}
}
}
Replace Team Logos
Use custom or higher quality logos:
{
"nba": {
"lakers": {
"aliases": [],
"override": {
"logo": "https://cdn.example.com/lakers-logo-4k.png",
"logoAlt": "https://cdn.example.com/lakers-logo-dark-4k.png"
}
}
}
}
Support Alternative Spellings
Handle variations in team names:
{
"mls": {
"lafc": {
"aliases": ["losangelesfc", "los angeles fc", "la fc"],
"override": {}
}
}
}
Troubleshooting
Override Not Working
Check your file:
- Ensure it’s valid JSON (use a JSON validator)
- Verify league keys are lowercase (
epl, notEPL) - Confirm team slugs are correct (use
/rawendpoint) - Check that underscores are replaced with hyphens
Verify volume mount:
docker exec <container-id> cat /app/teams.json
Check logs for errors:
docker logs <container-id>
Alias Not Matching
- Aliases are case-insensitive but must be exact matches (after normalization)
- Spaces are flexible (e.g., “man utd” matches “manutd”)
- Special characters are ignored during matching
- Check the alias is in the correct team’s entry
Changes Not Applied
- The
teams.jsonfile is loaded on server startup - Restart the container to reload changes:
docker restart <container-id>
Understanding “Team Not Found” Errors
When a team isn’t found, the error message includes all available teams from:
- The primary league
- All configured feeder leagues (if any)
- The fallback league (if configured)
Example for EPL:
{
"error": "Team not found: 'invalid-team' in EPL. Available teams: Arsenal, Aston Villa, ..., [Championship teams], [League One teams], [League Two teams]"
}
This comprehensive list helps you identify:
- The correct team name to use
- Whether the team exists in a feeder league
- All teams that can be matched for that league endpoint
For leagues with feeder leagues (EPL, La Liga, Bundesliga, etc.), the list includes teams from lower divisions, making it easier to find promoted/relegated teams.