A guide to formatting an RSS 2.0 feed so DEV.to imports your articles, images, and tags with zero formatting errors.
- Wrap full article HTML inside
<content:encoded><![CDATA[...]]></content:encoded>. - Convert all image
src,srcset, and linkhrefattributes to absolute URLs (https://domain.com/...). - Sanitize tags (
<category>): alphanumeric only (a-z0-9), max 20 chars, max 4 tags per post. - Provide a unique
<guid isPermaLink="true">to prevent duplicate imports. - Provide cover images via
<enclosure>and as the first<img>inside<content:encoded>. - In DEV Settings, keep "Mark RSS source as canonical" checked and "Replace self-referential links" unchecked.
| Field | Requirement | What It Does on DEV.to |
|---|---|---|
<title> |
Required | Article headline. Escape XML special characters. |
<link> |
Required | Canonical link back to original post. |
<guid> |
Required | Unique ID. Prevents re-importing duplicates on sync. |
<content:encoded> |
Required | Full HTML body wrapped in <![CDATA[...]]>. Converted to Markdown by DEV. |
<description> |
Fallback | Excerpt/summary. Used as body only if <content:encoded> is missing. |
<pubDate> |
Recommended | UTC date (Wed, 19 Aug 2026 10:00:00 GMT). Sets publication/draft date. |
<category> |
Optional (Max 4) | Becomes post tags. Must be alphanumeric and |
<enclosure> |
Optional | Sets the post's cover/hero image (type="image/webp" or image/png). |
<author> |
Optional | email@domain.com (Author Name) |
DEV.to rejects or corrupts tags that don't match [a-zA-Z0-9]:
-
Remove special chars:
next.js$\rightarrow$ nextjs,web-dev$\rightarrow$ webdev,c#$\rightarrow$ csharp. - Truncate: Maximum 20 characters per tag.
- Limit: Maximum 4 tags per post.
DEV.to cannot resolve relative paths like /images/hero.png.
- ❌
<img src="/images/hero.png"> - ✅
<img src="https://yourdomain.com/images/hero.png"> - ❌
<a href="/blog/my-post"> - ✅
<a href="https://yourdomain.com/blog/my-post">
To ensure the cover image renders both as the header banner and in feed previews:
- Add
<enclosure url="https://yourdomain.com/cover.webp" type="image/webp" length="0" />. - Prepend
<p><img src="https://yourdomain.com/cover.webp" alt="..." /></p>to<content:encoded>.
The bare minimum needed for DEV.to to ingest a post cleanly:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>My Developer Blog</title>
<link>https://example.com/blog</link>
<description>Clean developer tutorials and guides.</description>
<item>
<title>How to Deploy Next.js to Cloudflare</title>
<link>https://example.com/blog/nextjs-cloudflare</link>
<guid isPermaLink="true">https://example.com/blog/nextjs-cloudflare</guid>
<pubDate>Wed, 19 Aug 2026 10:00:00 GMT</pubDate>
<content:encoded><![CDATA[
<p>This is the full post body. All links like <a href="https://example.com/docs">Docs</a> must be absolute.</p>
]]></content:encoded>
</item>
</channel>
</rss><?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Engineering Blog</title>
<link>https://example.com/blog</link>
<description>Technical articles on web architecture and tooling.</description>
<language>en-us</language>
<lastBuildDate>Wed, 19 Aug 2026 21:00:00 GMT</lastBuildDate>
<atom:link href="https://example.com/rss.xml" rel="self" type="application/rss+xml" />
<item>
<title>Building Scalable RSS Pipelines</title>
<link>https://example.com/blog/scalable-rss-pipelines</link>
<guid isPermaLink="true">https://example.com/blog/scalable-rss-pipelines</guid>
<description>A guide to setting up automated RSS ingestion pipelines.</description>
<content:encoded><![CDATA[
<p><img src="https://example.com/images/cover.webp" alt="Building Scalable RSS Pipelines" /></p>
<p>Full HTML content rendered here. Use absolute paths for all media assets.</p>
<h2>Getting Started</h2>
<p>Visit <a href="https://example.com/start">our onboarding guide</a> to learn more.</p>
]]></content:encoded>
<pubDate>Wed, 19 Aug 2026 10:00:00 GMT</pubDate>
<author>team@example.com (Author Name)</author>
<category>webdev</category>
<category>javascript</category>
<category>nextjs</category>
<category>rss</category>
<enclosure url="https://example.com/images/cover.webp" type="image/webp" length="0" />
</item>
</channel>
</rss>Use these helper functions when building your RSS feed generator:
// 1. Sanitize XML special characters
export function escapeXml(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
}
// 2. Escape CDATA closing tags
export function escapeCdata(str: string): string {
return str.replace(/]]>/g, "]]]]><![CDATA[>")
}
// 3. Format tags for DEV.to (Alphanumeric only, max 20 chars, max 4 tags)
export function formatDevTags(rawTags: string[]): string[] {
const seen = new Set<string>()
const result: string[] = []
for (const raw of rawTags) {
const clean = raw.replace(/[^a-zA-Z0-9]/g, "").slice(0, 20)
const key = clean.toLowerCase()
if (!clean || seen.has(key)) continue
seen.add(key)
result.push(clean)
if (result.length === 4) break
}
return result
}
// 4. Convert all relative URLs (src, href, srcset) to absolute URLs
export function makeUrlsAbsolute(html: string, baseUrl: string): string {
return html.replace(/<[a-zA-Z][^<>]*>/g, (tag) =>
tag
.replace(
/\b(href|src)="(\/[^"]*)"/g,
(_, attr, val) => `${attr}="${new URL(val, baseUrl).toString()}"`
)
.replace(
/\bsrcset="([^"]*)"/g,
(_, val) => `srcset="${val.replace(/\/[^\s,]*/g, (p) => new URL(p, baseUrl).toString())}"`
)
)
}- Go to dev.to/settings/extensions.
- Scroll to "Publishing to DEV Community from RSS".
- Paste your feed URL (e.g.
https://yourdomain.com/rss.xml). - Set the options:
-
Mark the RSS source as canonical URL by default:
[x] Checked(Preserves your Google SEO ranking). -
Replace self-referential links with DEV Community-specific links:
[ ] Unchecked(Keeps internal links pointing to your website).
-
Mark the RSS source as canonical URL by default:
- Click "Submit feed settings"
$\rightarrow$ Click "Fetch feed now". - Go to dev.to/dashboard to view, edit, and publish your imported drafts.