Connect FlutterFlow to SpyFu by creating an API Group with base URL https://www.spyfu.com/apis, then adding GET calls to the domain_api and serp_api endpoint families with your API key and a target domain as query variables. SpyFu is competitor intelligence — use it to build a 'spy on a rival domain' app showing their most profitable organic keywords and paid ad history. Proxy the key through Firebase Cloud Functions.
| Fact | Value |
|---|---|
| Tool | SpyFu |
| Category | Marketing |
| Method | FlutterFlow API Call |
| Difficulty | Intermediate |
| Time required | 40 minutes |
| Last updated | July 2026 |
Build a Competitor Intelligence App with SpyFu and FlutterFlow
SpyFu's defining characteristic is its focus on competitor intelligence rather than your own site's data. While Ahrefs and Moz analyze your domain's authority and backlinks, and Serpstat helps you understand your own keyword rankings, SpyFu answers the question: 'What keywords and ads is my competitor buying and ranking for?' Its API surfaces a domain's most profitable organic keywords, estimated monthly clicks, paid search keywords, ad spend estimates, and historical ad copy — all from a competitor's public-facing footprint.
In FlutterFlow, SpyFu maps to two API endpoint families: domain_api (for organic keyword data, paid keyword data, and general domain intelligence) and serp_api (for SERP-level keyword ranking data). Each family has its own path under the base URL https://www.spyfu.com/apis, with different parameters per endpoint. Because these are distinct path-based endpoints rather than a single JSON-RPC endpoint like Serpstat, you will create separate FlutterFlow API Calls for each report you want to display — though they all share the same API Group and the same API key authentication pattern.
Authentication is via an API key query parameter (the exact parameter name varies by endpoint — SpyFu uses 'api_key' or 'secret_key' depending on the endpoint family; check your SpyFu API documentation). Access to the API is limited to higher SpyFu subscription plans. Rate limits vary by plan tier, and a busy ListView that re-fetches on scroll can hit the limit quickly on lower tiers.
Integration method
FlutterFlow connects to SpyFu through an API Group with base URL https://www.spyfu.com/apis, using GET requests to the domain_api and serp_api endpoint families with an API key as a query parameter. SpyFu returns JSON arrays of competitor keyword and ad data, which FlutterFlow parses via JSON Path and binds to ListViews. A Firebase Cloud Function proxy holds the API key server-side to prevent it from appearing in the compiled app bundle.
Prerequisites
- A SpyFu account with API access enabled on a higher subscription plan (verify which plan includes API access at spyfu.com/app/subscription)
- Your SpyFu API key from the SpyFu dashboard → Account → API
- A FlutterFlow project (free or paid) with a screen ready to display competitor keyword data
- A Firebase project for the Cloud Function proxy that holds your SpyFu API key
- Basic familiarity with FlutterFlow's API Calls panel and how to bind list data to a ListView
Step-by-step guide
Set up the Firebase Cloud Function proxy for SpyFu
A decompiled Flutter APK or IPA exposes every value in API Call query variables, including your SpyFu API key. Since SpyFu keys gate access to a paid plan's competitor intelligence data, an exposed key lets anyone drain your request quota. The Firebase Cloud Function proxy prevents this: FlutterFlow calls the proxy with only the domain and endpoint type as parameters; the proxy appends the secret API key before forwarding to SpyFu and returns clean JSON to the app. Create an HTTP Cloud Function. The function receives the target domain, the SpyFu endpoint type (e.g. 'organic_keywords', 'paid_keywords', 'serp'), and optional parameters (countryCode, page) as query parameters from FlutterFlow. It reads the API key from process.env.SPYFU_KEY, maps the endpoint type to the correct SpyFu URL path, appends all parameters including the key, and returns the SpyFu JSON response to FlutterFlow. Set the key: firebase functions:config:set spyfu.key='YOUR_KEY'. Add CORS headers for FlutterFlow web compatibility. Deploy with firebase deploy --only functions. Test by calling the function URL directly with ?domain=example.com&type=organic_keywords and confirming the SpyFu JSON response with a 'results' array.
1// Firebase Cloud Function proxy for SpyFu (functions/index.js)2const functions = require('firebase-functions');3const axios = require('axios');45// SpyFu endpoint families and their paths6const ENDPOINTS = {7 organic_keywords: '/domain_api/v2/organic_keywords/by_count?',8 paid_keywords: '/domain_api/v2/paid_keywords/by_count?',9 domain_stats: '/domain_api/v2/domain_stats/by_domain?',10 serp_results: '/serp_api/v2/results?'11};1213exports.spyfuProxy = functions.https.onRequest(async (req, res) => {14 res.set('Access-Control-Allow-Origin', '*');15 res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');16 if (req.method === 'OPTIONS') { res.status(204).send(''); return; }1718 const key = process.env.SPYFU_KEY;19 const type = req.query.type || 'organic_keywords';20 const domain = req.query.domain || '';21 const keyword = req.query.keyword || '';22 const countryCode = req.query.countryCode || 'US';23 const pageNum = req.query.pageNum || '1';24 const count = req.query.count || '10';2526 const endpointPath = ENDPOINTS[type];27 if (!endpointPath) {28 return res.status(400).json({ error: 'Invalid endpoint type' });29 }3031 const domainOrKw = type === 'serp_results' ? `keyword=${encodeURIComponent(keyword)}` : `domain=${encodeURIComponent(domain)}`;32 const url = `https://www.spyfu.com/apis${endpointPath}${domainOrKw}&countryCode=${countryCode}&pageNum=${pageNum}&count=${count}&api_key=${key}`;3334 try {35 const response = await axios.get(url, { timeout: 15000 });36 res.json(response.data);37 } catch (err) {38 const status = err.response?.status || 500;39 res.status(status).json({ error: err.message });40 }41});Pro tip: SpyFu's endpoint paths and parameter names are documented at spyfu.com/api — the exact path structure can change between API versions. Always verify against the official docs rather than guessing from the base URL alone.
Expected result: The Cloud Function is deployed and returns a SpyFu JSON response with a 'results' array when you call it with ?type=organic_keywords&domain=example.com.
Create the SpyFu API Group in FlutterFlow
Open FlutterFlow and navigate to API Calls in the left nav. Click + Add → Create API Group. Name it SpyFu. In the Base URL field, paste your Cloud Function URL: https://us-central1-YOUR_PROJECT.cloudfunctions.net/spyfuProxy. No Authorization header is needed at the group level — the proxy handles authentication internally. Save the group. Because SpyFu has two distinct API families (domain_api and serp_api), you will create two separate API Calls inside this group: one for domain intelligence (organic and paid keywords for a given domain) and one for SERP keyword data. Both point to the same proxy base URL but pass different 'type' parameters, which the proxy maps to the correct SpyFu path. Saving the group makes it available in the left nav API Calls panel. Note the group name — you will reference it when setting up button actions in later steps.
Pro tip: Keep the API Group named 'SpyFu' rather than something generic like 'Competitor API' — FlutterFlow shows the group name throughout the action editor, and a descriptive name saves confusion when you have multiple API Groups in a larger project.
Expected result: The SpyFu API Group is saved with your Cloud Function URL as the base URL and appears in the left nav.
Add API Calls for domain organic keywords and paid keywords
Inside the SpyFu group, you will create two API Calls: one for organic keyword data and one for paid keyword data. Both are GET requests that pass the same parameters with different 'type' values. Click + inside the SpyFu group → Create API Call. Name it Get Organic Keywords. Set the method to GET. Go to the Variables tab and add: - domain (String, required) — the competitor domain to analyze, e.g. competitor.com - countryCode (String, default: US) — US, UK, DE, AU, etc. - pageNum (Integer, default: 1) — pagination - count (Integer, default: 10) — results per page In the URL field, reference them: /?type=organic_keywords&domain={{domain}}&countryCode={{countryCode}}&pageNum={{pageNum}}&count={{count}} Switch to Response & Test. Enter a competitor domain and run the test. SpyFu returns a JSON object with a 'results' array where each item has: keyword, avgMonthlyClicks, rankingDifficulty, searchVolume, monthlyBudget. Click Generate JSON Paths. Extract: $.results[*].keyword → keywords, $.results[*].avgMonthlyClicks → clicks, $.results[*].searchVolume → volumes. Repeat to create a second API Call named Get Paid Keywords, with type=paid_keywords. The response structure is similar with additional fields like adBudget and adCount. Also add a third API Call Get Domain Stats using type=domain_stats which returns aggregate metrics (organicKeywords, paidKeywords, adBudget) for the competitor domain as a single object.
1// API Call URL patterns (set in FlutterFlow Variables tab)2// Organic keywords:3// /?type=organic_keywords&domain={{domain}}&countryCode={{countryCode}}&pageNum={{pageNum}}&count={{count}}4//5// Paid keywords:6// /?type=paid_keywords&domain={{domain}}&countryCode={{countryCode}}&pageNum={{pageNum}}&count={{count}}7//8// Domain stats:9// /?type=domain_stats&domain={{domain}}&countryCode={{countryCode}}10//11// SERP results (keyword search, not domain):12// /?type=serp_results&keyword={{keyword}}&countryCode={{countryCode}}&pageNum={{pageNum}}&count={{count}}1314// JSON Paths for organic_keywords response:15// $.results[*].keyword — keyword string list16// $.results[*].avgMonthlyClicks — estimated monthly clicks list17// $.results[*].searchVolume — monthly search volume list18// $.results[*].rankingDifficulty — difficulty score list (0-100)1920// JSON Paths for domain_stats response:21// $.results[0].organicKeywords — total organic keyword count22// $.results[0].paidKeywords — total paid keyword count23// $.results[0].adBudget — estimated monthly ad budgetPro tip: SpyFu's 'count' parameter has an upper limit that varies by plan. On lower tiers, requesting more than 10-25 results per page may be silently capped or rejected. Start with count=10 while testing.
Expected result: Three API Calls are created inside the SpyFu group: Get Organic Keywords, Get Paid Keywords, and Get Domain Stats. Each has a test result confirming JSON data is returned.
Build the competitor spy UI with a domain TextField and results ListView
The core UX for a SpyFu integration is a 'search a domain' pattern: one TextField where the user enters a competitor domain, a Search button, and a tabbed results view showing organic keywords and paid keywords as separate ListViews. On your main screen, add a TextField (hint: 'Enter competitor domain, e.g. competitor.com') and a large Search button below it. Add a TabBar with two tabs: 'Organic' and 'Paid'. Each tab contains a ListView for the corresponding keyword data. In the Search button's Actions panel: 1. Validate the TextField is not empty. If empty, show Snackbar: 'Please enter a competitor domain'. 2. Set isLoading = true (show CircularProgressIndicator, disable Search button). 3. Run three parallel actions: Get Organic Keywords, Get Paid Keywords, and Get Domain Stats API Calls, all with the TextField value as domain. 4. On all three succeeding: store the organic keyword list, paid keyword list, and domain stats in App State variables. Set isLoading = false. 5. On any error: show a Dialog with the error message and set isLoading = false. The Organic tab ListView uses the organic keywords App State list as its data source, with each item tile showing keyword name (bold), monthly search volume, and estimated monthly clicks. The Paid tab ListView mirrors this structure for paid keywords, adding the estimated ad budget as an additional chip. At the top of the results area (above the TabBar), add a Domain Stats card showing the competitor's total organic keyword count and estimated paid ad budget from the Get Domain Stats response — giving an instant overview before the user digs into the lists.
Pro tip: SpyFu data is competitor-facing (what other domains are doing), not self-analytics. Make this clear in your UI labels — e.g. 'Competitor Keywords for example.com' not 'Your Keywords'. This prevents user confusion about the data source.
Expected result: The competitor domain spy screen works end to end: entering a domain and tapping Search shows a domain stats card and two ListViews (organic and paid keywords) populated with SpyFu data.
Handle rate limits, pagination, and device testing
SpyFu rate limits scale with plan tier. On a lower plan, a quick repeated tapping of Search, or a ListView that re-fetches on scroll instead of loading from App State, can hit the cap and return 429 errors. Guard against this with two patterns. First, store the domain searched last (App State variable: lastSpyfuDomain) and the timestamp. When the user searches the same domain again within 10 minutes, show the cached App State data rather than re-calling the API. This covers the common pattern of browsing between tabs and returning to the same competitor. Second, implement pagination for keyword lists. SpyFu's results are paginated (pageNum, count parameters). Add a 'Load more' button at the bottom of each ListView. When tapped, it calls the same API Call with pageNum incremented by 1 and appends the new results to the existing App State list rather than replacing it. This avoids loading all 50+ keywords at once, which can exceed plan limits on a single call. For device testing, FlutterFlow's browser Run mode works fine since the Cloud Function handles CORS. Export to a test APK or use FlutterFlow's Preview on a connected device to confirm the full flow on mobile. No platform-specific permissions (camera, location, HealthKit) are needed for this integration — it is purely HTTP-based. If you'd rather skip the proxy setup and have a FlutterFlow expert wire the full SpyFu integration for you, RapidDev's team builds integrations like this every week — free scoping call at rapidevelopers.com/contact.
Pro tip: SpyFu returns a 'totalAvailableResults' field in the domain_api responses. Store this in App State and use it to show a 'Page X of Y' indicator and decide when to hide the 'Load more' button.
Expected result: Rate-limit protection and pagination are working. The 'Load more' button appends additional keywords without replacing cached results. Device testing confirms the app works on both mobile and web.
Common use cases
Competitor organic keyword spy tool
Build a 'spy on a competitor' app where a user types any domain and sees that domain's top organic keywords from SpyFu — including monthly search volume, current ranking position, and estimated monthly clicks. The app calls the domain_api organic keywords endpoint, parses the JSON array, and displays results in a ListView sorted by estimated traffic. The user can tap any keyword to see its SERP data via a serp_api call.
A competitor keyword spy app where a user types a competitor's domain and sees their top organic keywords with monthly search volume and estimated clicks, sorted by traffic value.
Copy this prompt to try it in FlutterFlow
Paid search ad history explorer
Build a paid search intelligence screen where a marketing team enters a competitor domain and sees the keywords that domain is currently buying on Google Ads, along with estimated monthly ad spend and average ad position. The app calls the domain_api paid keywords endpoint, displays results in a ListView with spend estimates, and lets the team save high-value keywords to a Supabase table for later targeting in their own campaigns.
An ad intelligence app showing a competitor domain's paid search keywords, estimated monthly spend, and ad copy history from SpyFu, with the ability to save interesting keywords.
Copy this prompt to try it in FlutterFlow
SERP ranking tracker for competitor monitoring
Build a keyword monitoring screen where the user enters a specific keyword and sees which domains are currently ranking for it in the Google SERP, along with their estimated monthly clicks. The app calls SpyFu's serp_api to get the current keyword SERP data and displays the ranking domains in a sorted card list. This lets founders monitor who they are competing against for a specific term without needing to manually check Google.
A SERP monitoring app where a user types a keyword and sees which domains rank for it along with their estimated monthly clicks, powered by SpyFu's SERP API.
Copy this prompt to try it in FlutterFlow
Troubleshooting
403 Forbidden — 'API access is not available on your current plan'
Cause: SpyFu API access requires a higher subscription plan. The Starter or Basic tiers do not include API access; it is available on Professional and Team plans (verify current plan tiers at spyfu.com/app/subscription).
Solution: Log into your SpyFu account and check your subscription level under Account → Subscription. If API access is not shown, you will need to upgrade your plan to access the API endpoints. Contact SpyFu support to confirm which plan tier includes API access if it is not clearly listed.
Results array is empty for a domain that has data in the SpyFu web app
Cause: The 'countryCode' parameter may be set to the wrong region. SpyFu stores separate databases per country, so a domain with US data returns empty results if you query the UK database (countryCode=UK).
Solution: Confirm the countryCode parameter matches the target market. SpyFu uses two-letter country codes: US, GB (not UK), DE, AU, CA. Also verify the domain is entered without https:// or www prefixes — SpyFu's domain_api typically expects a bare domain like 'example.com', not 'https://www.example.com'.
XMLHttpRequest error in FlutterFlow Run mode — no response
Cause: CORS error. If the API Group base URL points to www.spyfu.com/apis instead of your Cloud Function, the browser blocks the cross-origin GET request from FlutterFlow's web-based Run mode.
Solution: Confirm the SpyFu API Group's base URL in FlutterFlow is your Firebase Cloud Function URL, not a SpyFu URL. The Cloud Function adds Access-Control-Allow-Origin: * to all responses, enabling CORS-compliant browser requests from Run mode.
429 Too Many Requests — rate limit hit during development
Cause: Rapid consecutive Search button taps during testing, or a widget data source that re-fetches on scroll, can quickly exceed SpyFu's per-plan rate limit.
Solution: Disable the Search button while a request is in flight (bind its disabled state to an isLoading App State variable). Move all data sources from widget-level API Calls to App State and only trigger API Calls from button actions. Add a 10-minute cache check that skips re-fetching when the domain was recently queried.
Best practices
- Never put the SpyFu API key in a FlutterFlow query variable — it will be embedded in the compiled binary and decompilable. Always proxy through Firebase Cloud Functions with the key in environment variables.
- Frame the UI clearly as competitor intelligence — label results as 'Keywords for [competitor domain]' rather than generic 'Keywords' — SpyFu shows competitor data, not your own site's analytics.
- Use two distinct API families correctly: domain_api for domain-based keyword and ad data, serp_api for keyword-based SERP rankings. Mixing up the parameter sets returns empty or invalid results.
- Implement pagination from the start rather than requesting 50+ results per call — paginating with count=10 keeps each API call within plan limits and makes the app feel faster with faster initial loads.
- Cache the last queried domain and timestamp in App State and skip re-fetching if data is less than 10 minutes old — this protects against accidental quota drain from repeated searches during a single session.
- Disable the Search button and show a loading indicator while the API call is in flight — SpyFu calls can take 2-4 seconds, and without a disabled state, users may tap multiple times and trigger duplicate requests.
- Always pass countryCode as a user-selectable dropdown (US, GB, DE, AU, CA) rather than hardcoding it — SpyFu's value is in regional data, and hardcoding limits your app to one market.
Alternatives
Choose Serpstat if your focus is your own domain's keyword rankings and research rather than competitor intelligence — Serpstat is more affordable and covers both owned-domain and competitor data with a cleaner JSON-RPC API.
Choose SEMrush if you need the deepest competitor intelligence with advertising data, traffic analytics, and keyword gaps — SEMrush has more data than SpyFu but requires CSV parsing in FlutterFlow and a higher per-unit cost.
Choose Ahrefs if backlink analysis and Domain Rating are your primary competitive intelligence needs — Ahrefs provides deeper link data than SpyFu but has no ad intelligence and requires an Enterprise API plan.
Frequently asked questions
Is SpyFu an SEO tool or a paid-search tool?
SpyFu covers both, but its unique strength is paid-search intelligence — it is the only tool in this category that prominently surfaces competitor Google Ads keywords, estimated ad spend, and historical ad copy. The domain_api provides both organic and paid keyword data, while serp_api focuses on organic SERP rankings. If competitor PPC intelligence is what you need, SpyFu is the strongest choice in this group.
Can I use SpyFu to analyze my own domain's performance?
Technically yes — you can enter your own domain just like a competitor's. However, SpyFu is optimized for competitive analysis and shows the same data for your domain that it shows for rivals (estimated organic traffic, paid keywords, etc.). For owned-domain analytics using verified first-party data, tools like Ahrefs or SEMrush with a connected account are more accurate. SpyFu's strength is the comparative, competitive view.
Why do I need two separate API endpoint families for SpyFu?
SpyFu separates its data into two API families with different query patterns: domain_api accepts a 'domain' parameter and returns all keyword and ad data associated with that domain, while serp_api accepts a 'keyword' parameter and returns which domains currently rank for that keyword. You use domain_api to 'spy on a competitor domain' and serp_api to 'find who is ranking for a specific keyword'. Build separate FlutterFlow screens or tabs for each use case.
Does the integration work in FlutterFlow's web Run mode?
Yes, as long as you use the Cloud Function proxy. Direct calls from the browser to www.spyfu.com/apis fail due to CORS restrictions. The Cloud Function adds Access-Control-Allow-Origin: * headers and proxies the request, so FlutterFlow's browser-based Run mode works correctly. Native iOS and Android builds also work identically through the proxy.
What plan do I need for SpyFu API access?
SpyFu API access is available on higher subscription tiers — typically Professional or Team plans. The Starter plan does not include API access. Verify the current plan requirements at spyfu.com/app/subscription, as plan names and feature inclusions can change. Rate limits and the number of results per call also vary by plan tier.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation