Last week I wrote about why I added internal linking to my image converter. This is the technical follow-up: how I replaced alphabetical ordering with a semantic scoring algorithm.
The problem with alphabetical ordering
My RelatedConversions component was showing links in alphabetical order. For /heic-to-jpg, it would show avif-to-heic, avif-to-jpg, bmp-to-heic — technically related, but not semantically prioritized.
What I wanted: show conversions that share the most format overlap first, then factor in keyword similarity.
The scoring model: 70/30
A simple weighted formula:
- format overlap — how many formats the two conversions share (weight: 0.7)
- keyword similarity — do the slugs share meaningful terms (weight: 0.3)
function scoreRelation(current, candidate) {
const [fromA, toA] = current.split('-to-');
const [fromB, toB] = candidate.split('-to-');
const formatsA = new Set([fromA, toA]);
const formatsB = new Set([fromB, toB]);
const shared = [...formatsA].filter(f => formatsB.has(f)).length;
const formatScore = shared / Math.max(formatsA.size, formatsB.size);
const wordsA = new Set(current.split('-'));
const wordsB = new Set(candidate.split('-'));
const sharedWords = [...wordsA].filter(w => wordsB.has(w) && w !== 'to').length;
const keywordScore = sharedWords / Math.max(wordsA.size, wordsB.size);
return (formatScore * 0.7) + (keywordScore * 0.3);
}
How it works in practice
For /heic-to-jpg:
-
jpg-to-heic→ score 1.0 (both formats shared) -
heic-to-png→ score 0.7 (one shared format: heic) -
webp-to-jpg→ score 0.7 (one shared format: jpg) -
avif-to-png→ score 0.0 (no shared formats)
The component
export default function RelatedConversions({ from, to }) {
const current = `${from}-to-${to}`;
const ranked = SLUGS
.filter(slug => slug !== current)
.map(slug => ({ slug, score: scoreRelation(current, slug) }))
.sort((a, b) => b.score - a.score)
.slice(0, 8);
return (
<section>
<h2>Related Conversions</h2>
{ranked.map(({ slug }) => (
<a key={slug} href={`/${slug}`}>
{slug.replace('-to-', ' to ').toUpperCase()}
</a>
))}
</section>
);
}
What's next
Planning to weight by GSC impression data — pages that already rank should get higher weight in related links. That closes the feedback loop: organic traffic signals inform which related conversions to surface.
Building in public at convertifyapp.net.
Top comments (0)