Skip to main content

RankFabric Engine - Client Integration Guide

Base URL

https://rankfabric-edge.grocerybundles.workers.dev

Authentication

All requests must include an API Key in the Authorization header:

Authorization: Bearer sk_live_YOUR_API_KEY

Important: Do NOT use a Base44 proxy function. Call the RankFabric Engine directly from your React app.


React Integration Example

Setup API Client (RankFabricEngine.jsx)

import axios from 'axios';

const RANKFABRIC_API_URL = 'https://rankfabric-edge.grocerybundles.workers.dev';

// Get API key from Base44 organization settings
const getApiKey = () => {
// TODO: Store in organization settings or environment
return 'sk_live_YOUR_API_KEY';
};

export const rankFabricAPI = axios.create({
baseURL: RANKFABRIC_API_URL,
headers: {
'Authorization': `Bearer ${getApiKey()}`,
'Content-Type': 'application/json'
}
});

// API Methods
export const RankFabricEngine = {

// Track keyword - Returns instant SERP data + sets up daily tracking
async trackKeyword({ project_id, keyword_text, location_code = 2840, language_code = 'en' }) {
const response = await rankFabricAPI.post('/api/keywords/track', {
project_id,
keyword_text,
location_code,
language_code
});
return response.data;
},

// List all tracked keywords with enrichment data
async getKeywords(project_id) {
const response = await rankFabricAPI.get('/api/subscriptions', {
params: { project_id }
});
return response.data;
},

// Get unified rankings (SEO + App Store + Local)
async getRankings(project_id, filters = {}) {
const response = await rankFabricAPI.get('/api/rankings', {
params: { project_id, ...filters }
});
return response.data.rankings;
},

// List assets (websites, apps)
async listAssets(project_id) {
const response = await rankFabricAPI.get('/api/assets', {
params: { project_id }
});
return response.data.assets;
},

// Add asset
async addAsset({ project_id, type, value, name, role }) {
const response = await rankFabricAPI.post('/api/assets', {
project_id,
type, // 'website' | 'app'
value, // 'nike.com' | 'app_id'
name,
role // 'primary' | 'competitor'
});
return response.data;
},

// Portfolio trends (aggregated search volume over time)
async getPortfolioTrends(project_id, source = 'google_ads', limit = 24) {
const response = await rankFabricAPI.get('/api/keywords/portfolio-trends', {
params: { project_id, source, limit }
});
return response.data;
}
};

Key Integration Points

1. Keyword Tracking Page

Add Keyword Button:

const handleAddKeyword = async (keywordText) => {
try {
const result = await RankFabricEngine.trackKeyword({
project_id: currentProject.id,
keyword_text: keywordText,
location_code: 2840 // US
});

// Result includes instant SERP data
console.log('Top 100 results:', result.serp_data);

// Keyword is now tracked daily
refetchKeywords();
} catch (error) {
console.error('Failed to track keyword:', error);
}
};

Keyword List Table:

const { data: keywords } = useQuery({
queryKey: ['keywords', projectId],
queryFn: () => RankFabricEngine.getKeywords(projectId)
});

// Display columns:
// - keyword_text
// - search_volume (from enrichment)
// - cpc
// - competition
// - status (from subscription)

2. Rankings Dashboard

Unified Rankings Table:

const { data: rankings } = useQuery({
queryKey: ['rankings', projectId],
queryFn: () => RankFabricEngine.getRankings(projectId)
});

// Rankings include:
// - keyword (for SEO)
// - position
// - url
// - channel ('SEO', 'app_store', 'local')
// - platform ('Google', 'Bing', 'Apple', 'Google Play')
// - check_ts (timestamp)

Chart showing total search volume over time:

const { data: trends } = useQuery({
queryKey: ['portfolio-trends', projectId],
queryFn: () => RankFabricEngine.getPortfolioTrends(projectId)
});

// Use trends.monthly_trends for chart:
// [{ year: 2025, month: 11, total_search_volume: 1234567 }, ...]

Data Storage Strategy

✅ DO Store in Base44 Postgres:

  • projects table with id, name, created_at
  • User → Project relationships
  • UI preferences, settings

❌ DON'T Store in Base44 Postgres:

  • Keywords (query from Engine via /api/subscriptions)
  • Rankings data (query from Engine via /api/rankings)
  • SERP results (returned live, stored in Engine's D1)
  • Search volumes, CPC, competition (stored in Engine after enrichment)

Why?

The Engine is the single source of truth for SEO/ASO data. Your Postgres should only store:

  1. Project metadata
  2. User preferences
  3. Organization settings

Enrichment Flow (Automatic)

When you call /api/keywords/track, the Engine automatically:

  1. ✅ Returns instant SERP data (Top 100)
  2. ✅ Creates daily tracking subscription
  3. ✅ Queues background enrichment job
  4. ✅ Fetches from DataForSEO Keyword Overview:
    • 84 months of historical search volume
    • Current search volume, CPC, competition
    • Clickstream data (real user behavior)
    • Demographics (age, gender)
    • Backlink metrics

Timeline:

  • Instant: SERP data (0-2 seconds)
  • Background: Enrichment data (5-30 seconds)
  • Daily: Updated SERP rankings (scheduled)

To check if enrichment completed:

const keywords = await RankFabricEngine.getKeywords(project_id);
// If keyword.search_volume is not null, enrichment is done

Error Handling

try {
const result = await RankFabricEngine.trackKeyword({...});
} catch (error) {
if (error.response?.status === 401) {
// Invalid or missing API key
console.error('Authentication failed');
} else if (error.response?.status === 400) {
// Bad request (missing project_id, etc)
console.error('Validation error:', error.response.data.error);
} else if (error.response?.status === 404) {
// Project not found
console.error('Project does not exist');
} else {
// Network or server error
console.error('Request failed:', error.message);
}
}

Common Issues

❌ 404 Error: /functions/rankFabricProxy

Problem: You're calling a Base44 proxy function that doesn't exist. Solution: Call the RankFabric Engine directly (see React example above).

❌ Keywords not showing search volume

Problem: Enrichment hasn't completed yet. Solution: Wait 5-30 seconds after tracking, then refetch. Check keyword.search_volume !== null.

❌ CORS errors

Problem: Calling from wrong origin or missing CORS headers. Solution: Ensure you're calling from https://base44.app (CORS is configured for this).


API Reference

Track Keyword

POST /api/keywords/track

{
"project_id": "proj_123",
"keyword_text": "best crm software",
"location_code": 2840,
"language_code": "en",
"device": "desktop"
}

Response:

{
"success": true,
"keywords_queued": 1,
"keywords": [{
"keyword_id": "kw_abc123",
"keyword_text": "best crm software"
}],
"serp_data": {
"items": [
{
"type": "organic",
"rank_absolute": 1,
"url": "https://example.com",
"title": "Best CRM Software 2025",
"description": "..."
}
]
}
}

Get Subscriptions (Keywords)

GET /api/subscriptions?project_id=proj_123

Response:

{
"subscriptions": [{
"id": "sub_123",
"keyword_text": "best crm software",
"search_volume": 49500,
"cpc": 17.62,
"competition": 0.06,
"keyword_difficulty": 64,
"location_code": 2840,
"status": "active",
"next_check": 1763996924315
}]
}

Get Rankings

GET /api/rankings?project_id=proj_123

Optional Filters:

  • ?platform=google (google, bing, apple, google_play)
  • ?channel=seo (seo, app_store, local)
  • ?limit=200 (default: 200)

Response:

{
"rankings": [{
"keyword_text": "best crm software",
"rank_absolute": 5,
"url": "https://yoursite.com/crm",
"domain": "yoursite.com",
"channel": "SEO",
"platform": "Google",
"relationship": "MINE",
"check_ts": 1763910524315
}]
}

GET /api/keywords/portfolio-trends?project_id=proj_123

Parameters:

  • source: google_ads | bing_normalized | clickstream_normalized (default: google_ads)
  • limit: Number of months (default: 24)

Response:

{
"summary": {
"total_keywords": 26,
"total_current_search_volume": 1234567,
"avg_current_search_volume": 47483
},
"monthly_trends": [
{
"year": 2025,
"month": 11,
"total_search_volume": 1234567
}
],
"clickstream_trends": [
{
"year": 2025,
"month": 11,
"total_clickstream_volume": 987654,
"avg_female_pct": 52.3,
"avg_male_pct": 47.7,
"avg_age_18_24_pct": 15.2
}
]
}

Next Steps

  1. Remove the rankFabricProxy function call from your React app
  2. Use the RankFabricEngine client shown above
  3. Store API key in your organization settings (not hardcoded)
  4. Test with proj_2fae47dd1fabc10e (test project that has data)