To integrate Replit with SEMrush, store your SEMrush API key in Replit Secrets (lock icon in sidebar), then call the SEMrush API from a server-side Express or Flask backend. You can retrieve keyword rankings, domain analytics, and backlink data programmatically. Deploy on Replit Autoscale for on-demand SEO reporting tools or scheduled keyword tracking dashboards.
Why Integrate SEMrush with Replit?
SEMrush is one of the most powerful SEO platforms available, offering a comprehensive REST API that lets you pull keyword rankings, organic traffic estimates, domain authority scores, backlink profiles, and competitor keyword gaps directly into your applications. By integrating SEMrush with Replit, you can build custom SEO dashboards, automate keyword research workflows, and create reporting tools tailored to your exact business needs β all without being limited to SEMrush's native UI.
Replit gives you a fully managed server environment where you can run Node.js or Python backends 24/7. Combined with SEMrush's API, you can create endpoints that aggregate SEO data on demand, schedule daily keyword tracking jobs, or build client-facing SEO reporting portals. This is especially valuable for SEO agencies, content marketers, and product teams who need SEO data integrated into their own tools and dashboards.
The SEMrush API uses straightforward API key authentication and returns data in CSV or JSON format depending on the endpoint. Most keyword data endpoints are included in SEMrush's Guru and Business plans. With Replit's Secrets panel, your API key stays encrypted and out of your source code, meeting security best practices while keeping your development workflow smooth.
Integration method
SEMrush integrates with Replit through direct REST API calls from your server-side code. You store your SEMrush API key securely in Replit Secrets and make authenticated HTTP requests to the SEMrush API endpoints from an Express or Flask backend running in your Repl. This gives you programmatic access to keyword data, domain metrics, and competitive intelligence without exposing credentials in your code.
Prerequisites
- A SEMrush account with API access (Guru or Business plan β API is not available on Pro plan)
- Your SEMrush API key from semrush.com/api (under your account settings)
- A Replit account with a Node.js or Python Repl created
- Basic familiarity with REST APIs and JSON responses
- Node.js with axios/node-fetch or Python with requests library installed in your Repl
Step-by-step guide
Store Your SEMrush API Key in Replit Secrets
Store Your SEMrush API Key in Replit Secrets
Before writing any code, secure your SEMrush API key using Replit's built-in Secrets manager. Open your Repl and look for the lock icon (π) in the left sidebar β clicking it opens the Secrets panel. Create a new secret with the key name SEMRUSH_API_KEY and paste your SEMrush API key as the value. Your API key is found in your SEMrush account under Account Settings > API. Never put your API key directly in your code files β Replit's Secret Scanner will flag hardcoded credentials and your key would be exposed if you ever share or publish your Repl. Secrets are encrypted at rest and injected as environment variables at runtime, meaning your code accesses them via process.env.SEMRUSH_API_KEY in Node.js or os.environ['SEMRUSH_API_KEY'] in Python. After adding the secret, restart your Repl to ensure the environment variable is available. The Secrets panel also lets you add multiple keys for different environments, so you could store a SEMRUSH_API_KEY_TEST alongside your production key if needed.
Pro tip: SEMrush API keys are tied to your account plan. If you're on a free trial, API access may be limited to a small number of requests per day β check your API usage at semrush.com/api/analytics/.
Expected result: Your SEMRUSH_API_KEY secret appears in the Secrets panel and is accessible as an environment variable when your Repl runs.
Set Up Your Express Server with SEMrush API Client
Set Up Your Express Server with SEMrush API Client
Create a Node.js Express server that acts as a proxy between your frontend and the SEMrush API. The SEMrush API uses a simple query parameter-based authentication model β you append your API key to each request URL. The base URL for most SEMrush data endpoints is https://api.semrush.com/. Different report types are accessed via the type parameter (e.g., domain_organic for organic keywords, phrase_this for keyword data). Responses are returned in pipe-delimited format by default, but you can request JSON-like data by structuring your queries appropriately. Install the axios package by running npm install axios in the Replit Shell, then create your server file. The Express server should expose endpoints that your frontend (or other services) can call, while keeping the SEMrush API key securely on the server side. Always validate and sanitize input parameters before passing them to the SEMrush API to prevent injection attacks.
1const express = require('express');2const axios = require('axios');34const app = express();5app.use(express.json());67const SEMRUSH_API_KEY = process.env.SEMRUSH_API_KEY;8const SEMRUSH_BASE_URL = 'https://api.semrush.com/';910// Get organic keywords for a domain11app.get('/api/domain-keywords', async (req, res) => {12 const { domain, database = 'us', limit = 10 } = req.query;1314 if (!domain) {15 return res.status(400).json({ error: 'domain parameter is required' });16 }1718 try {19 const params = new URLSearchParams({20 type: 'domain_organic',21 key: SEMRUSH_API_KEY,22 domain,23 database,24 display_limit: limit,25 export_columns: 'Ph,Po,Nq,Cp,Co,Tr,Tc,Nr,Td'26 });2728 const response = await axios.get(`${SEMRUSH_BASE_URL}?${params}`);29 const lines = response.data.trim().split('\n');30 const headers = lines[0].split(';');31 const rows = lines.slice(1).map(line => {32 const values = line.split(';');33 return headers.reduce((obj, header, i) => {34 obj[header] = values[i];35 return obj;36 }, {});37 });3839 res.json({ domain, database, keywords: rows });40 } catch (error) {41 console.error('SEMrush API error:', error.message);42 res.status(500).json({ error: 'Failed to fetch keyword data' });43 }44});4546// Get keyword overview data47app.get('/api/keyword-overview', async (req, res) => {48 const { phrase, database = 'us' } = req.query;4950 if (!phrase) {51 return res.status(400).json({ error: 'phrase parameter is required' });52 }5354 try {55 const params = new URLSearchParams({56 type: 'phrase_this',57 key: SEMRUSH_API_KEY,58 phrase,59 database,60 export_columns: 'Ph,Nq,Cp,Co,Nr,Td'61 });6263 const response = await axios.get(`${SEMRUSH_BASE_URL}?${params}`);64 const lines = response.data.trim().split('\n');65 const headers = lines[0].split(';');66 const data = headers.reduce((obj, header, i) => {67 obj[header] = lines[1] ? lines[1].split(';')[i] : null;68 return obj;69 }, {});7071 res.json({ phrase, database, overview: data });72 } catch (error) {73 console.error('SEMrush API error:', error.message);74 res.status(500).json({ error: 'Failed to fetch keyword overview' });75 }76});7778app.listen(3000, '0.0.0.0', () => {79 console.log('SEMrush proxy server running on port 3000');80});Pro tip: SEMrush returns data in semicolon-delimited format for most endpoints. The export_columns parameter controls which fields are returned β check the SEMrush API docs for column codes like Ph (phrase), Nq (search volume), Cp (CPC), and Po (position).
Expected result: Your Express server starts without errors. Visiting /api/domain-keywords?domain=example.com in the Replit preview returns a JSON array of organic keyword data.
Build a Python Flask Alternative
Build a Python Flask Alternative
If you prefer Python, you can achieve the same SEMrush integration using Flask and the requests library. Python is a natural choice for SEO data processing because of the rich ecosystem of data manipulation libraries like pandas and the ease of writing CSV/JSON parsing code. Install Flask and requests by running pip install flask requests in the Replit Shell. The Python version parses the SEMrush semicolon-delimited response format and converts it to a clean Python dictionary before returning JSON to the client. For production use with the Python version, consider adding caching with functools.lru_cache or a Redis client to avoid burning through SEMrush API units on repeated requests for the same domain. The SEMrush API has daily and monthly unit limits depending on your subscription tier β domain_organic queries typically cost 10 API units per request, while phrase_this costs 1 unit.
1import os2import requests3from flask import Flask, request, jsonify45app = Flask(__name__)67SEMRUSH_API_KEY = os.environ['SEMRUSH_API_KEY']8SEMRUSH_BASE_URL = 'https://api.semrush.com/'910def parse_semrush_response(text):11 """Parse SEMrush semicolon-delimited response into list of dicts."""12 lines = text.strip().split('\n')13 if len(lines) < 2:14 return []15 headers = lines[0].split(';')16 results = []17 for line in lines[1:]:18 values = line.split(';')19 results.append(dict(zip(headers, values)))20 return results2122@app.route('/api/domain-keywords')23def domain_keywords():24 domain = request.args.get('domain')25 database = request.args.get('database', 'us')26 limit = request.args.get('limit', 10)2728 if not domain:29 return jsonify({'error': 'domain parameter is required'}), 4003031 params = {32 'type': 'domain_organic',33 'key': SEMRUSH_API_KEY,34 'domain': domain,35 'database': database,36 'display_limit': limit,37 'export_columns': 'Ph,Po,Nq,Cp,Co,Tr,Tc,Nr,Td'38 }3940 try:41 response = requests.get(SEMRUSH_BASE_URL, params=params, timeout=15)42 response.raise_for_status()43 keywords = parse_semrush_response(response.text)44 return jsonify({'domain': domain, 'database': database, 'keywords': keywords})45 except requests.RequestException as e:46 return jsonify({'error': f'SEMrush API error: {str(e)}'}), 5004748@app.route('/api/keyword-overview')49def keyword_overview():50 phrase = request.args.get('phrase')51 database = request.args.get('database', 'us')5253 if not phrase:54 return jsonify({'error': 'phrase parameter is required'}), 4005556 params = {57 'type': 'phrase_this',58 'key': SEMRUSH_API_KEY,59 'phrase': phrase,60 'database': database,61 'export_columns': 'Ph,Nq,Cp,Co,Nr,Td'62 }6364 try:65 response = requests.get(SEMRUSH_BASE_URL, params=params, timeout=15)66 response.raise_for_status()67 data = parse_semrush_response(response.text)68 return jsonify({'phrase': phrase, 'database': database, 'overview': data[0] if data else {}})69 except requests.RequestException as e:70 return jsonify({'error': f'SEMrush API error: {str(e)}'}), 5007172if __name__ == '__main__':73 app.run(host='0.0.0.0', port=3000)Pro tip: Monitor your SEMrush API unit consumption carefully. Each API call type costs a different number of units β check the SEMrush API documentation for a full unit cost table before building high-frequency applications.
Expected result: Your Flask server starts and the /api/domain-keywords endpoint returns parsed JSON data when called with a domain parameter.
Configure Replit Deployment for Production
Configure Replit Deployment for Production
Once your SEMrush integration is working locally, configure your Repl for production deployment. For a keyword research API or dashboard backend, Replit Autoscale is the recommended deployment type β it scales to zero when not in use (saving costs) and spins up quickly when requests arrive. Autoscale is ideal for SEMrush integrations because SEO tool usage is typically bursty rather than constant. Create or update your .replit file to specify the run command and port configuration. For high-traffic SEO tools that need to be always available, consider Reserved VM deployment instead, which provides a persistent server at a fixed monthly cost. Add CORS headers to your server if you're calling the API from a separate frontend domain. SEMrush API responses can be slow (1-3 seconds) for large datasets, so implement proper timeout handling and consider caching frequently requested domain data in memory or a simple file-based cache to reduce API unit consumption.
1# .replit configuration for Node.js deployment2# Add this to your .replit file34# For Node.js:5# [deployment]6# run = ["node", "server.js"]7# deploymentTarget = "cloudrun"8#9# [[ports]]10# internalPort = 300011# externalPort = 801213# For Python:14# [deployment]15# run = ["python", "app.py"]16# deploymentTarget = "cloudrun"17#18# [[ports]]19# internalPort = 300020# externalPort = 802122# Add CORS to Node.js server (install: npm install cors)23const cors = require('cors');24app.use(cors({25 origin: process.env.ALLOWED_ORIGIN || '*'26}));2728# Simple in-memory cache for SEMrush responses29const cache = new Map();30const CACHE_TTL = 3600000; // 1 hour in milliseconds3132function getCached(key) {33 const entry = cache.get(key);34 if (entry && Date.now() - entry.timestamp < CACHE_TTL) {35 return entry.data;36 }37 return null;38}3940function setCached(key, data) {41 cache.set(key, { data, timestamp: Date.now() });42}Pro tip: Add the ALLOWED_ORIGIN secret in Replit Secrets to restrict which domains can call your SEMrush proxy API β this prevents others from using your SEMrush API units if your Replit URL becomes publicly known.
Expected result: Your Repl deploys successfully on Autoscale and the SEMrush API endpoints are accessible via your Replit deployment URL.
Common use cases
Automated Keyword Ranking Dashboard
Build a web app that pulls organic keyword rankings for any domain from SEMrush on demand. Users enter a domain and country, and your Replit backend queries the SEMrush Organic Research API, returning the top keywords, their positions, search volumes, and traffic estimates in a clean table.
Build a keyword research tool that takes a domain and country code as input, calls the SEMrush API to get the top 20 organic keywords, and displays the results in a sortable table showing keyword, position, search volume, and CPC.
Copy this prompt to try it in Replit
Competitor Keyword Gap Analysis
Create a tool that compares two domains' keyword profiles using the SEMrush API. Your Replit backend fetches keywords for both domains, finds gaps where a competitor ranks but you don't, and outputs a prioritized list of keyword opportunities based on search volume and difficulty.
Build a competitor analysis tool that accepts two domain names, queries SEMrush for their organic keyword lists, identifies keywords where domain A ranks but domain B doesn't, and returns the top opportunities sorted by monthly search volume.
Copy this prompt to try it in Replit
Daily SEO Report Email Bot
Schedule a Replit backend to run daily, pulling keyword position changes for a set of target keywords via the SEMrush API, then formatting the results as a summary report. Combine with SendGrid to email the report to stakeholders every morning automatically.
Build a daily SEO monitoring script that reads a list of target keywords from a config file, queries SEMrush for their current rankings, compares them to yesterday's data stored in a local JSON file, and outputs a change summary showing which keywords moved up or down.
Copy this prompt to try it in Replit
Troubleshooting
API returns 'ERROR 50 :: NOTHING FOUND' for a domain
Cause: SEMrush doesn't have ranking data for the specified domain in the chosen database/country. This is common for very new domains, domains with low traffic, or when querying a country database where the domain has no presence.
Solution: Try a different database code (e.g., 'uk' instead of 'us'), or check if the domain is indexed in SEMrush by searching it directly at semrush.com. For new domains with no data, SEMrush simply won't have results yet.
API returns 'ERROR 120 :: INVALID API KEY'
Cause: Your SEMRUSH_API_KEY secret is missing, incorrectly spelled, or the key itself has been revoked or expired.
Solution: Open the Replit Secrets panel (lock icon π) and verify the secret name is exactly SEMRUSH_API_KEY with no extra spaces. Copy your current API key from semrush.com/api and update the secret value. Restart your Repl after updating the secret.
1// Add a startup check to catch missing credentials early2if (!process.env.SEMRUSH_API_KEY) {3 console.error('ERROR: SEMRUSH_API_KEY environment variable is not set');4 process.exit(1);5}API returns 'ERROR 130 :: WRONG API UNITS BALANCE' or requests fail after working initially
Cause: You've exhausted your SEMrush API unit balance for the billing period. Different report types cost different numbers of units β domain_organic costs 10 units per request, which can add up quickly in a development environment.
Solution: Check your API unit balance at semrush.com/api. Implement response caching to avoid redundant API calls during development. Cache results for at least 1 hour for keyword data (which doesn't change minute-to-minute). Consider using SEMrush's batch export features for large datasets instead of making many individual API calls.
1// Check remaining API units before making requests2const checkUnits = async () => {3 const params = new URLSearchParams({4 type: 'api_units',5 key: process.env.SEMRUSH_API_KEY6 });7 const response = await axios.get(`https://api.semrush.com/?${params}`);8 return parseInt(response.data.trim());9};Server returns 500 errors and console shows 'ECONNREFUSED' or timeout errors
Cause: Replit free-tier Repls may have restricted outbound network access. Additionally, the SEMrush API server can occasionally be slow, causing request timeouts if your timeout value is too low.
Solution: Ensure your Repl is on a plan that allows outbound HTTP requests. Increase the request timeout in axios to at least 15-20 seconds. Implement retry logic with exponential backoff for transient failures.
1const response = await axios.get(url, {2 timeout: 20000, // 20 second timeout3 headers: { 'User-Agent': 'Replit-SEMrush-Integration/1.0' }4});Best practices
- Always store your SEMrush API key in Replit Secrets (lock icon π) β never hardcode it in your source files, as Replit's Secret Scanner will flag exposed credentials
- Implement response caching with at least a 1-hour TTL for keyword and domain data, since SEO metrics don't change in real-time and caching dramatically reduces API unit consumption
- Monitor your SEMrush API unit balance programmatically and add alerts when balance drops below a threshold β units are consumed per request type and don't roll over on most plans
- Use Replit Autoscale deployment for SEO tools with bursty usage patterns; switch to Reserved VM only if you need guaranteed sub-second cold start times
- Always validate the domain or keyword input before sending it to the SEMrush API to prevent unnecessary API unit consumption on invalid inputs
- Handle SEMrush's semicolon-delimited response format carefully β domains or keywords containing semicolons can break naive string splitting; use a proper CSV parser for production code
- Respect SEMrush's rate limits (typically 10 requests per second on most plans) by implementing request queuing if you're processing bulk keyword lists
- Log SEMrush API errors to Replit's console output and consider writing an error log file so you can audit failed requests without losing the error context
Alternatives
Ahrefs is the stronger choice if backlink analysis is your primary need, with a more comprehensive link database than SEMrush.
Moz is a good alternative if Domain Authority scoring is your main use case, offering a simpler API with generous free tier limits.
Serpstat offers similar keyword and SERP tracking at a significantly lower price point, making it a budget-friendly SEMrush alternative.
SpyFu is the better option when competitor PPC keyword intelligence is your primary goal, with deeper Google Ads historical data than SEMrush.
Frequently asked questions
How do I connect Replit to SEMrush?
Store your SEMrush API key in Replit Secrets (the lock icon π in the sidebar) as SEMRUSH_API_KEY. Then access it in your server code via process.env.SEMRUSH_API_KEY (Node.js) or os.environ['SEMRUSH_API_KEY'] (Python) and make HTTP requests to https://api.semrush.com/ with your key as a query parameter.
Does Replit work with SEMrush for free?
Replit itself is free to use for development. However, SEMrush API access requires a Guru or Business plan subscription β the SEMrush API is not available on the free or Pro plans. Check semrush.com/api for current plan requirements and API unit allocations.
How do I store my SEMrush API key safely in Replit?
Use Replit Secrets: click the lock icon (π) in the left sidebar, add a new secret named SEMRUSH_API_KEY, and paste your key as the value. Secrets are encrypted and injected as environment variables β they're never visible in your source code or accessible to other Replit users.
Why is SEMrush returning semicolon-separated data instead of JSON?
SEMrush's legacy API endpoints return pipe or semicolon-delimited text format by default. You need to parse this in your code by splitting on newlines (for rows) and semicolons (for columns). The first row contains the column headers. The examples in this guide show how to parse this format into clean JSON.
Can I run scheduled keyword tracking with Replit and SEMrush?
Yes β use Replit's Scheduled deployment type for cron-like execution. Create a script that queries SEMrush for your tracked keywords and saves the results to a file or database, then configure the scheduled deployment to run it daily. Combine with SendGrid or Slack to receive automatic reports.
What SEMrush API endpoints are most useful for a Replit integration?
The most commonly used endpoints are domain_organic (organic keyword rankings for a domain), phrase_this (metrics for a specific keyword), domain_rank (domain overview with traffic estimates), and backlinks_overview (backlink profile summary). Check the SEMrush API documentation at developer.semrush.com for the full list with unit costs.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation