Internal Links API
Automatically add internal links to your content based on keywords you configure. No need to read this if you are using WordPress It works out of the box.
Overview
Internal links are essential for SEO and user navigation. With the Internal Links API, you can:
- Define keyword-to-URL mappings in your MassBlogger dashboard
- Fetch these mappings via API when rendering your content
- Automatically replace keywords with links in your blog posts
- Maintain consistent internal linking across all your content
Endpoint
GET
/api/internal-linksReturns all internal links configured for your website.
Query Parameters
| apiKey | Required | Your website API key |
Example Request
GET https://www.massblogger.com/api/internal-links?apiKey=YOUR_API_KEYResponse Format
The API returns an array of keyword-URL pairs:
contact us→
/contactpricing→
/pricingbest practices→
/blog/best-practicesgetting started→
/docs/getting-startedkeywordstringThe keyword to search for in your contenturlstringThe URL to link to when the keyword is foundUsage Examples
Next.js (App Router)
// lib/internal-links.js
const API_KEY = process.env.MASSBLOGGER_API_KEY;
const API_URL = 'https://www.massblogger.com';
export async function getInternalLinks() {
const res = await fetch(
`${API_URL}/api/internal-links?apiKey=${API_KEY}`,
{ next: { revalidate: 3600 } } // Cache for 1 hour
);
return res.json();
}
export function applyInternalLinks(content, links, currentSlug) {
let result = content;
links.forEach(({ keyword, url }) => {
if (!keyword || !url) return;
// Skip links that point to the current page
if (currentSlug && url.endsWith('/' + currentSlug)) return;
const esc = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let found = false;
result = result.replace(
// Match headings, existing links, HTML tags, or the keyword
new RegExp('(<h[1-6][^>]*>[\\s\\S]*?</h[1-6]>)|(<a[^>]*>[\\s\\S]*?</a>)|(<[^>]+>)|(\\b' + esc + '\\b)', 'gi'),
(m, h, a, t, kw) => {
if (h || a || t) return m; // Skip headings, links, tags
if (!found && kw) {
found = true;
return '<a href="' + url + '" class="internal-link">' + kw + '</a>';
}
return m;
}
);
});
return result;
}Usage in a blog post page:
// app/blog/[slug]/page.js
import { getInternalLinks, applyInternalLinks } from '@/lib/internal-links';
export default async function BlogPost({ params }) {
const { slug } = await params;
const [post, links] = await Promise.all([
getPost(slug),
getInternalLinks()
]);
const contentWithLinks = applyInternalLinks(post.content, links, slug);
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: contentWithLinks }} />
</article>
);
}React (Client-side)
import { useState, useEffect } from 'react';
function useInternalLinks(apiKey) {
const [links, setLinks] = useState([]);
useEffect(() => {
fetch('https://www.massblogger.com/api/internal-links?apiKey=' + apiKey)
.then(res => res.json())
.then(setLinks)
.catch(console.error);
}, [apiKey]);
return links;
}
function applyInternalLinks(content, links, currentSlug) {
let result = content;
links.forEach(({ keyword, url }) => {
if (!keyword || !url) return;
if (currentSlug && url.endsWith('/' + currentSlug)) return;
const esc = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let found = false;
result = result.replace(
new RegExp('(<h[1-6][^>]*>[\\s\\S]*?</h[1-6]>)|(<a[^>]*>[\\s\\S]*?</a>)|(<[^>]+>)|(\\b' + esc + '\\b)', 'gi'),
(m, h, a, t, kw) => {
if (h || a || t) return m;
if (!found && kw) { found = true; return '<a href="' + url + '">' + kw + '</a>'; }
return m;
}
);
});
return result;
}
// Usage in component
function BlogPost({ post }) {
const links = useInternalLinks('your_api_key');
const content = applyInternalLinks(post.content, links, post.slug);
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}Vanilla JavaScript
const API_KEY = 'your_api_key';
async function fetchInternalLinks() {
const response = await fetch(
'https://www.massblogger.com/api/internal-links?apiKey=' + API_KEY
);
return response.json();
}
function applyInternalLinks(content, links, currentSlug) {
let result = content;
links.forEach(({ keyword, url }) => {
if (!keyword || !url) return;
if (currentSlug && url.endsWith('/' + currentSlug)) return;
const esc = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let found = false;
result = result.replace(
new RegExp('(<h[1-6][^>]*>[\\s\\S]*?</h[1-6]>)|(<a[^>]*>[\\s\\S]*?</a>)|(<[^>]+>)|(\\b' + esc + '\\b)', 'gi'),
function(m, h, a, t, kw) {
if (h || a || t) return m;
if (!found && kw) { found = true; return '<a href="' + url + '">' + kw + '</a>'; }
return m;
}
);
});
return result;
}
// Usage
document.addEventListener('DOMContentLoaded', async () => {
const links = await fetchInternalLinks();
const article = document.querySelector('.article-content');
// Extract current slug from URL path
const currentSlug = window.location.pathname.split('/').pop();
if (article) {
article.innerHTML = applyInternalLinks(article.innerHTML, links, currentSlug);
}
});PHP
<?php
$api_key = 'your_api_key';
function getInternalLinks($api_key) {
$url = "https://www.massblogger.com/api/internal-links?apiKey=" . $api_key;
$response = file_get_contents($url);
return json_decode($response, true);
}
function applyInternalLinks($content, $links, $current_slug = '') {
foreach ($links as $link) {
$keyword = $link['keyword'];
$url = $link['url'];
if (empty($keyword) || empty($url)) continue;
// Skip links that point to the current page
if ($current_slug && str_ends_with($url, '/' . $current_slug)) continue;
$esc = preg_quote($keyword, '/');
// Skip matches inside headings, existing links, or HTML tags
$pattern = '/(<h[1-6][^>]*>[\\s\\S]*?<\\/h[1-6]>)|(<a[^>]*>[\\s\\S]*?<\\/a>)|(<[^>]+>)|(\\b' . $esc . '\\b)/i';
$found = false;
$content = preg_replace_callback($pattern, function($m) use ($url, &$found) {
if (!empty($m[1]) || !empty($m[2]) || !empty($m[3])) return $m[0];
if (!$found && !empty($m[4])) {
$found = true;
return '<a href="' . htmlspecialchars($url) . '">' . $m[4] . '</a>';
}
return $m[0];
}, $content);
}
return $content;
}
// Usage
$links = getInternalLinks($api_key);
$post_content = get_the_content(); // Your content source
$current_slug = basename(get_permalink()); // Current page slug
$content_with_links = applyInternalLinks($post_content, $links, $current_slug);
echo $content_with_links;
?>Best Practices
- Cache responses: Internal links don't change often. Cache the API response for at least 1 hour to reduce API calls.
- Limit replacements: Only replace the first occurrence of each keyword to avoid over-linking, which can hurt SEO and readability.
- Use whole word matching: Use word boundaries in your regex to avoid matching partial words.
- Process server-side: For SEO benefits, apply internal links on the server before sending HTML to the client.
- Avoid nested links: Be careful not to insert links inside existing anchor tags. Consider parsing HTML properly for complex content.
- Skip self-links: Never link a page to itself. Pass the current slug and skip any internal link whose URL matches the current page.
- Skip headings: Never insert links inside heading tags (h1–h6). Internal links belong in paragraph text only.
- Order by length: Process longer keywords first to avoid partial matches (e.g., "getting started guide" before "getting started").
Need help? Contact us at [email protected]