Gap Analysis
Compares keyword frequencies between a target text and multiple comparison texts to identify keyword usage gaps. This node is essential for competitive content analysis, helping you understand how your content's keyword usage compares to top-ranking competitors or industry standards.
Common Properties
- Name - The custom name of the node.
- Color - The custom color of the node.
- Delay Before (sec) - Waits in seconds before executing the node.
- Delay After (sec) - Waits in seconds after executing node.
- Continue On Error - Automation will continue regardless of any error. The default value is false.
If the ContinueOnError property is true, no error is caught when the project is executed, even if a Catch node is used.
Inputs
-
Self Keyword Counts - Keyword frequency counts from your target text. This should be an object with keywords as keys and counts as values, typically output from the Count Occurrences node. Example:
{
"seo": 5,
"content marketing": 3,
"optimization": 2
} -
Other Keyword Counts - Array of keyword count objects from comparison texts (e.g., competitor pages, top-ranking content). Each object should have the same structure as Self Keyword Counts. Example:
[
{"seo": 8, "content marketing": 5, "optimization": 6},
{"seo": 7, "content marketing": 4, "optimization": 5},
{"seo": 6, "content marketing": 6, "optimization": 4}
]
Output
- Keywords - An object showing the gap analysis for each keyword, containing your count and the average count from comparison texts. Example:
{
"seo": {
"self": 5,
"average": 7.0
},
"content marketing": {
"self": 3,
"average": 5.0
},
"optimization": {
"self": 2,
"average": 5.0
}
}
How It Works
The Gap Analysis node helps identify keyword opportunities and deficiencies:
- Receives your keyword counts and an array of competitor keyword counts
- Calculates the average count for each keyword across all comparison texts
- Compares your counts against the calculated averages
- Returns both values for each keyword, enabling easy gap identification
This allows you to see where your content underuses or overuses keywords compared to the average of competitor content.
Practical Examples
Example 1: Basic Competitive Analysis
Compare your blog post against top 3 ranking competitors:
// Step 1: Count keywords in your content
msg.text = msg.yourBlogPost;
msg.keywords = ["SEO", "optimization", "ranking", "keywords", "content"];
// After Count Occurrences node
const yourCounts = msg.counts;
// Step 2: Count same keywords in competitor content
const competitorTexts = [msg.competitor1, msg.competitor2, msg.competitor3];
msg.competitorCounts = [];
// Use a Loop node to process each competitor
for (let competitorText of competitorTexts) {
msg.text = competitorText;
msg.keywords = ["SEO", "optimization", "ranking", "keywords", "content"];
// After Count Occurrences in loop
msg.competitorCounts.push({...msg.counts});
}
// Step 3: Perform Gap Analysis
msg.counts = yourCounts; // Self Keyword Counts
msg.other_counts = msg.competitorCounts; // Other Keyword Counts
// After Gap Analysis node
const gaps = msg.keywords;
// Step 4: Identify gaps
for (let keyword in gaps) {
const gap = gaps[keyword];
const difference = gap.average - gap.self;
if (difference > 2) {
console.log(`⚠️ Under-optimized: "${keyword}" - You: ${gap.self}, Competitors: ${gap.average}`);
} else if (difference < -2) {
console.log(`⚠️ Over-optimized: "${keyword}" - You: ${gap.self}, Competitors: ${gap.average}`);
} else {
console.log(`✓ Good: "${keyword}" - You: ${gap.self}, Competitors: ${gap.average}`);
}
}
Example 2: Content Optimization Recommendations
Generate specific recommendations based on gap analysis:
// After Gap Analysis
const gaps = msg.keywords;
msg.recommendations = [];
for (let keyword in gaps) {
const gap = gaps[keyword];
const difference = gap.average - gap.self;
const percentageDiff = (difference / gap.average * 100).toFixed(1);
if (difference > 0) {
const recommended = Math.ceil(gap.average);
msg.recommendations.push({
keyword: keyword,
current: gap.self,
competitor_avg: gap.average,
recommended: recommended,
add: recommended - gap.self,
priority: difference > 3 ? "High" : difference > 1 ? "Medium" : "Low",
message: `Add "${keyword}" ${recommended - gap.self} more times (currently ${gap.self}, competitors average ${gap.average.toFixed(1)})`
});
}
}
// Sort by priority
msg.recommendations.sort((a, b) => {
const priority = { High: 3, Medium: 2, Low: 1 };
return priority[b.priority] - priority[a.priority];
});
console.log("Content Optimization Recommendations:");
msg.recommendations.forEach((rec, index) => {
console.log(`${index + 1}. [${rec.priority}] ${rec.message}`);
});
Example 3: Multi-Page Site Analysis
Analyze keyword usage across your entire website compared to competitors:
// Your website pages
const yourPages = [
{ url: "/home", content: msg.homeContent },
{ url: "/services", content: msg.servicesContent },
{ url: "/about", content: msg.aboutContent }
];
// Competitor pages
const competitorSites = [
{ pages: [msg.comp1Home, msg.comp1Services, msg.comp1About] },
{ pages: [msg.comp2Home, msg.comp2Services, msg.comp2About] }
];
const targetKeywords = ["professional services", "consulting", "expertise", "solutions"];
// Aggregate counts for your pages
let yourAggregate = {};
targetKeywords.forEach(kw => yourAggregate[kw] = 0);
for (let page of yourPages) {
msg.text = page.content;
msg.keywords = targetKeywords;
// After Count Occurrences
for (let kw in msg.counts) {
yourAggregate[kw] += msg.counts[kw];
}
}
// Aggregate counts for competitors
let competitorAggregates = [];
for (let competitor of competitorSites) {
let compAggregate = {};
targetKeywords.forEach(kw => compAggregate[kw] = 0);
for (let pageContent of competitor.pages) {
msg.text = pageContent;
msg.keywords = targetKeywords;
// After Count Occurrences
for (let kw in msg.counts) {
compAggregate[kw] += msg.counts[kw];
}
}
competitorAggregates.push(compAggregate);
}
// Perform Gap Analysis
msg.counts = yourAggregate;
msg.other_counts = competitorAggregates;
// After Gap Analysis
console.log("Site-wide Keyword Gap Analysis:");
for (let keyword in msg.keywords) {
console.log(`${keyword}: Your site: ${msg.keywords[keyword].self}, Competitors: ${msg.keywords[keyword].average}`);
}
Example 4: Tracking Content Improvements
Monitor how content updates affect keyword gaps:
// Before content update
msg.text = msg.originalContent;
msg.keywords = msg.targetKeywords;
// After Count Occurrences
const beforeCounts = {...msg.counts};
// After content update
msg.text = msg.updatedContent;
// After Count Occurrences
const afterCounts = {...msg.counts};
// Compare both against competitors
msg.other_counts = msg.competitorCounts; // Same competitor data
// Gap Analysis for original content
msg.counts = beforeCounts;
// After Gap Analysis
const beforeGaps = {...msg.keywords};
// Gap Analysis for updated content
msg.counts = afterCounts;
// After Gap Analysis
const afterGaps = msg.keywords;
// Generate improvement report
console.log("Content Update Impact:");
for (let keyword in afterGaps) {
const before = beforeGaps[keyword];
const after = afterGaps[keyword];
const improvement = after.self - before.self;
const beforeGap = before.average - before.self;
const afterGap = after.average - after.self;
console.log(`\n${keyword}:`);
console.log(` Added: ${improvement} occurrences`);
console.log(` Gap before: ${beforeGap.toFixed(1)}`);
console.log(` Gap after: ${afterGap.toFixed(1)}`);
console.log(` Gap reduced by: ${(beforeGap - afterGap).toFixed(1)}`);
}
Example 5: Industry Benchmark Comparison
Compare against industry-standard content from multiple sources:
// Collect industry-standard articles
const industryBenchmarks = [
msg.topRankingArticle1,
msg.topRankingArticle2,
msg.industryLeaderContent,
msg.authorityBlogPost1,
msg.authorityBlogPost2
];
msg.keywords = ["best practices", "industry standards", "compliance", "regulations"];
// Count in all benchmarks
msg.benchmarkCounts = [];
for (let benchmark of industryBenchmarks) {
msg.text = benchmark;
// After Count Occurrences
msg.benchmarkCounts.push({...msg.counts});
}
// Count in your content
msg.text = msg.yourIndustryContent;
// After Count Occurrences
const yourCounts = msg.counts;
// Gap Analysis
msg.counts = yourCounts;
msg.other_counts = msg.benchmarkCounts;
// After Gap Analysis
const gaps = msg.keywords;
// Create compliance report
msg.complianceReport = {
totalKeywords: Object.keys(gaps).length,
meetingBenchmark: 0,
belowBenchmark: 0,
details: []
};
for (let keyword in gaps) {
const gap = gaps[keyword];
const status = gap.self >= gap.average ? "Meeting" : "Below";
if (status === "Meeting") msg.complianceReport.meetingBenchmark++;
else msg.complianceReport.belowBenchmark++;
msg.complianceReport.details.push({
keyword: keyword,
yourCount: gap.self,
industryAverage: gap.average,
status: status
});
}
console.log(`Compliance Score: ${msg.complianceReport.meetingBenchmark}/${msg.complianceReport.totalKeywords} keywords meeting industry standards`);
Tips for Effective Use
-
Competitor Selection
- Choose 3-5 top-ranking competitors for accurate averages
- Use pages that target the same keywords/topics
- Include diverse sources for broader perspective
-
Keyword Lists
- Use the same keyword list for all comparisons
- Include both primary and secondary keywords
- Consider variations and related terms
-
Interpreting Results
- Small gaps (±1-2) are usually acceptable
- Large negative gaps suggest under-optimization
- Large positive gaps might indicate keyword stuffing
- Consider context - not all keywords need equal frequency
-
Taking Action
- Prioritize keywords with largest negative gaps
- Don't blindly match competitor averages - quality matters
- Update content naturally and contextually
- Re-analyze after making changes
-
Data Quality
- Ensure comparison texts are relevant and current
- Use sufficient comparison sources (3+ recommended)
- Clean text data before counting (remove boilerplate, navigation, etc.)
Common Errors and Solutions
Issue: All Gaps Show Zero
Cause: Self keyword counts and other keyword counts might be identical or empty.
Solution:
- Verify that you're comparing different texts
- Check that Count Occurrences nodes are working correctly
- Ensure keyword lists are identical across all counts
Issue: Average Values Seem Wrong
Cause: Inconsistent keyword counting or missing data in comparison texts.
Solution:
- Verify all comparison texts were processed
- Check that all texts use the same keyword list
- Ensure no texts in the array are empty or null
Issue: Keywords Missing from Results
Cause: Gap Analysis only includes keywords that exist in the self counts.
Solution:
- Ensure your target text was analyzed with all keywords
- The keywords in self counts determine which keywords appear in results
- Add missing keywords to your initial keyword list
Best Practices
-
Regular Monitoring
- Run gap analysis monthly for important pages
- Track changes in competitor keyword usage
- Monitor impact of your content updates
-
Contextual Analysis
- Don't rely solely on numbers
- Consider keyword placement (titles, headings, etc.)
- Evaluate content quality alongside keyword counts
-
Balanced Optimization
- Avoid keyword stuffing to match competitors
- Maintain natural, readable content
- Focus on user value, not just keyword counts
-
Comprehensive Strategy
- Combine with TF-IDF Analysis for keyword importance
- Use Cluster Keywords to find related terms
- Monitor overall content quality metrics
Performance Considerations
- Very fast computation, even with many keywords
- Scales linearly with number of comparison texts
- Can process hundreds of keywords efficiently
- Memory usage is minimal
Related Nodes
- Count Occurrences - Generate keyword counts for gap analysis
- TF-IDF Analysis - Identify which keywords are most important
- Frequency Analysis - Extract keywords with occurrence data
- Cluster Keywords - Group similar keywords for broader analysis