Documentation Index Fetch the complete documentation index at: https://docs.fieldfunded.com/llms.txt
Use this file to discover all available pages before exploring further.
Build a Chrome Extension That Shows Odds on Sports Articles
Reading a match preview on ESPN or BBC Sport? This extension detects team names and injects real-time odds directly into the page.
What You’ll Use
SDK Method Endpoint Purpose search()GET /v1/searchMatch team names found in articles getEventOdds()GET /v1/events/{id}/oddsGet odds for matched events
How It Works
User reads ESPN article about "Barcelona vs Real Madrid"
↓
Content script detects team names
↓
Background script calls search("Barcelona")
↓
Gets odds for the matched event
↓
Injects tooltip next to team names showing odds
Step 1: Manifest V3
{
"manifest_version" : 3 ,
"name" : "Sports Odds Overlay" ,
"version" : "1.0" ,
"description" : "See live odds while reading sports articles" ,
"permissions" : [ "storage" ],
"host_permissions" : [
"https://api.fieldfunded.com/*"
],
"content_scripts" : [
{
"matches" : [
"*://*.espn.com/*" ,
"*://*.bbc.com/sport/*" ,
"*://*.skysports.com/*"
],
"js" : [ "content.js" ],
"css" : [ "overlay.css" ]
}
],
"background" : {
"service_worker" : "background.js"
},
"options_page" : "options.html"
}
Step 2: Background Script (API Calls)
// background.js — handles all API communication
const API_KEY = '' ; // Set via options page
const BASE_URL = 'https://api.fieldfunded.com/v1' ;
// Cache to avoid repeated API calls
const cache = new Map < string , any >();
chrome . runtime . onMessage . addListener (( msg , sender , sendResponse ) => {
if ( msg . type === 'SEARCH_TEAM' ) {
const cached = cache . get ( msg . team );
if ( cached ) {
sendResponse ( cached );
return true ;
}
fetch ( ` ${ BASE_URL } /search?q= ${ encodeURIComponent ( msg . team ) } &limit=1` , {
headers: { 'X-API-Key' : API_KEY },
})
. then ( r => r . json ())
. then ( async ( data ) => {
if ( data . events && data . events . length > 0 ) {
const event = data . events [ 0 ];
// Fetch odds
const oddsRes = await fetch ( ` ${ BASE_URL } /events/ ${ event . id } /odds` , {
headers: { 'X-API-Key' : API_KEY },
});
const odds = await oddsRes . json ();
const result = { event , odds };
cache . set ( msg . team , result );
// Cache expires after 5 minutes
setTimeout (() => cache . delete ( msg . team ), 5 * 60 * 1000 );
sendResponse ( result );
} else {
sendResponse ( null );
}
});
return true ; // Async response
}
});
Step 3: Content Script (Team Detection + Tooltip)
// content.js — detects team names and injects tooltips
// Common team names to look for
const TEAMS = [
'Barcelona' , 'Real Madrid' , 'Manchester United' , 'Manchester City' ,
'Liverpool' , 'Arsenal' , 'Chelsea' , 'Juventus' , 'Bayern Munich' ,
'PSG' , 'AC Milan' , 'Inter Milan' , 'Atletico Madrid' , 'Dortmund' ,
'Lakers' , 'Warriors' , 'Celtics' , 'Patriots' , 'Chiefs' ,
// Add more or load dynamically from getSports()/getLeagues()
];
function scanForTeams () {
const textNodes : Node [] = [];
const walker = document . createTreeWalker (
document . body ,
NodeFilter . SHOW_TEXT ,
null
);
while ( walker . nextNode ()) {
textNodes . push ( walker . currentNode );
}
const processed = new Set < string >();
for ( const node of textNodes ) {
const text = node . textContent || '' ;
for ( const team of TEAMS ) {
if ( text . includes ( team ) && ! processed . has ( team )) {
processed . add ( team );
// Ask background script for odds
chrome . runtime . sendMessage (
{ type: 'SEARCH_TEAM' , team },
( result ) => {
if ( result && result . odds ?. markets ?. length > 0 ) {
injectTooltip ( node , team , result );
}
}
);
}
}
}
}
function injectTooltip ( textNode : Node , team : string , data : any ) {
const parent = textNode . parentElement ;
if ( ! parent ) return ;
const html = parent . innerHTML ;
const market = data . odds . markets [ 0 ];
const oddsStr = market . selections
. map (( s : any ) => ` ${ s . name } : ${ s . odds } ` )
. join ( ' • ' );
const tooltip = `<span class="ff-odds-trigger"> ${ team } <span class="ff-odds-tooltip">
<strong> ${ data . event . home_team } vs ${ data . event . away_team } </strong><br>
${ market . name } : ${ oddsStr }
</span></span>` ;
parent . innerHTML = html . replace ( team , tooltip );
}
// Run on page load
scanForTeams ();
/* overlay.css */
.ff-odds-trigger {
position : relative ;
border-bottom : 2 px dotted #53FC18 ;
cursor : pointer ;
}
.ff-odds-tooltip {
display : none ;
position : absolute ;
bottom : 100 % ;
left : 50 % ;
transform : translateX ( -50 % );
background : #1a1a2e ;
color : #ffffff ;
padding : 8 px 12 px ;
border-radius : 6 px ;
font-size : 13 px ;
white-space : nowrap ;
z-index : 10000 ;
box-shadow : 0 4 px 12 px rgba ( 0 , 0 , 0 , 0.3 );
border : 1 px solid #53FC18 ;
}
.ff-odds-trigger:hover .ff-odds-tooltip {
display : block ;
}
Rate Limit Math
Each unique team name found = 2 requests (search + odds)
Aggressive caching (5 min) means repeat visits cost 0
A typical article mentions 2-4 teams = 4-8 requests per page
Free tier handles ~1,000 article reads per month
Search API Reference See search endpoint docs →
Get Your Free API Key Start building in 5 minutes — 10,000 free requests/month