Cloudflare Workers changed how I think about building software. Zero cold starts. Global distribution. Generous free tier. For real estate applications where milliseconds matter, it's the perfect platform.
This guide walks you through building a property valuation API from scratch.
Why Edge Computing for PropTech?
Traditional servers sit in one location. When a user in Phoenix requests data from a server in Virginia, that request travels 2,000 miles each way. Add database queries, and you're looking at 500ms+ response times.
Workers run on Cloudflare's network of 300+ data centers. Your code executes at the location nearest your user. That same Phoenix request now travels maybe 50 miles.
Real impact: Our valuation API averages 89ms response time globally. Traditional server-based competitors? 400-800ms.In real estate, that speed difference means:
Setting Up Your Environment
First, install Wrangler (Cloudflare's CLI):
npm install -g wrangler
wrangler login
Create a new Worker:
wrangler init property-api
cd property-api
Building the Valuation Endpoint
Replace the generated src/index.js with:
export default {
async fetch(request, env) {
// Handle CORS
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
});
}
// Only accept POST
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
try {
const { arv, condition, market } = await request.json();
// Validate inputs
if (!arv || !condition) {
return jsonResponse({ error: 'Missing required fields' }, 400);
}
// Calculate offer
const result = calculateOffer(arv, condition, market);
return jsonResponse(result);
} catch (e) {
return jsonResponse({ error: 'Invalid request' }, 400);
}
}
};
function calculateOffer(arv, condition, market = 'stable') {
// Condition multipliers
const conditionFactors = {
excellent: 0.95,
good: 0.88,
fair: 0.80,
poor: 0.70
};
// Market adjustments
const marketFactors = {
hot: 1.05,
stable: 1.00,
cold: 0.92
};
const conditionFactor = conditionFactors[condition] || 0.80;
const marketFactor = marketFactors[market] || 1.00;
// Base calculation: 70% of ARV, adjusted for condition and market
const baseOffer = arv * 0.70;
const adjustedOffer = baseOffer conditionFactor marketFactor;
const maxOffer = Math.round(adjustedOffer);
// Calculate potential ROI
const estimatedProfit = arv - maxOffer;
const roi = ((estimatedProfit / maxOffer) * 100).toFixed(1);
return {
maxOffer,
arv,
estimatedProfit,
roi: parseFloat(roi),
breakdown: {
baseOffer: Math.round(baseOffer),
conditionAdjustment: conditionFactor,
marketAdjustment: marketFactor
},
timestamp: new Date().toISOString()
};
}
function jsonResponse(data, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
Deploy and Test
Deploy to Cloudflare:
wrangler deploy
You'll get a URL like https://property-api.your-subdomain.workers.dev. Test it:
curl -X POST https://property-api.your-subdomain.workers.dev \
-H "Content-Type: application/json" \
-d '{"arv": 350000, "condition": "good", "market": "stable"}'
Response:
{
"maxOffer": 215600,
"arv": 350000,
"estimatedProfit": 134400,
"roi": 62.3,
"breakdown": {
"baseOffer": 245000,
"conditionAdjustment": 0.88,
"marketAdjustment": 1
},
"timestamp": "2026-01-12T15:30:00.000Z"
}
Adding a Database with D1
For storing leads or comps, add Cloudflare D1:
wrangler d1 create property-db
Update wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "property-db"
database_id = "your-database-id"
Create a table:
wrangler d1 execute property-db --command "CREATE TABLE leads (
id INTEGER PRIMARY KEY AUTOINCREMENT,
address TEXT NOT NULL,
arv INTEGER,
condition TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)"
Now you can query the database in your Worker:
const { results } = await env.DB.prepare(
"SELECT * FROM leads WHERE created_at > ?"
).bind(lastWeek).all();
Caching with KV
For data that doesn't change often (like zip code market data), use KV:
wrangler kv:namespace create MARKET_CACHE
// Check cache first
const cached = await env.MARKET_CACHE.get(market:${zipCode});
if (cached) {
return JSON.parse(cached);
}
// Fetch fresh data
const marketData = await fetchMarketData(zipCode);
// Cache for 24 hours
await env.MARKET_CACHE.put(
market:${zipCode},
JSON.stringify(marketData),
{ expirationTtl: 86400 }
);
Cost Breakdown
Cloudflare's free tier includes:
For most real estate operations, you'll never pay a cent. If you scale to enterprise level, pricing is still fractions of AWS/GCP.
What We Built With This
Our entire operation runs on Workers:
Total monthly cost: $0 (still on free tier with 50K+ requests/month).
Ready to build? Start with the Cloudflare Workers docs or check out our open-source valuation engine.