Contentful Favicon Complete Guide
Master favicon setup with Contentful headless CMS: Asset uploads, GraphQL/REST API queries, content models, and frontend integration for React, Next.js, Vue, and more.
Headless CMS Favicon Approach
1. Upload Assets
Store favicons in Contentful Media
2. Content Model
Create settings content type
3. Query & Render
Fetch via API in frontend
Step 1: Upload Favicon Assets
Contentful Media Library
Upload via Web Interface
- Log in to Contentful:
app.contentful.com - Select your Space
- Go to Media tab
- Click Add asset ? Upload files
- Upload all favicon files:
- favicon.ico
- favicon-16x16.png
- favicon-32x32.png
- favicon-96x96.png
- favicon-512x512.png
- apple-touch-icon.png
- android-chrome-192x192.png
- android-chrome-512x512.png
- Click Publish for each asset
- Note each asset's ID for reference
Upload via CLI (Automated)
# Install Contentful CLI
npm install -g contentful-cli
# Login
contentful login
# Select space
contentful space use
# Upload asset (example script)
contentful space asset create \
--file-path ./favicon.ico \
--file-name "favicon.ico" \
--title "Site Favicon" \
--description "Main site favicon"Step 2: Create Content Model
Site Settings Content Type
Create Content Type
- Go to Content model tab
- Click Add content type
- Name:
Site Settings - API Identifier:
siteSettings - Create
Add Favicon Fields
| Field Name | Field ID | Type | Settings |
|---|---|---|---|
| Favicon ICO | faviconIco | Media (one file) | Accept: image/x-icon |
| Favicon 16x16 | favicon16 | Media (one file) | Accept: image/png |
| Favicon 32x32 | favicon32 | Media (one file) | Accept: image/png |
| Apple Touch Icon | appleTouchIcon | Media (one file) | Accept: image/png |
Create Settings Entry
- Go to Content tab
- Click Add entry ? Site Settings
- Link uploaded favicon assets to each field
- Click Publish
Step 3: Query with GraphQL
Fetch Favicon Data
GraphQL Query
query {
siteSettingsCollection(limit: 1) {
items {
faviconIco {
url
title
description
}
favicon16 {
url
width
height
}
favicon32 {
url
width
height
}
appleTouchIcon {
url
width
height
}
}
}
}Example Response
{
"data": {
"siteSettingsCollection": {
"items": [
{
"faviconIco": {
"url": "//images.ctfassets.net/space_id/asset_id/favicon.ico",
"title": "Site Favicon",
"description": "Main favicon"
},
"favicon16": {
"url": "//images.ctfassets.net/space_id/asset_id/favicon-16x16.png",
"width": 16,
"height": 16
},
"favicon32": {
"url": "//images.ctfassets.net/space_id/asset_id/favicon-32x32.png",
"width": 32,
"height": 32
},
"appleTouchIcon": {
"url": "//images.ctfassets.net/space_id/asset_id/apple-touch-icon.png",
"width": 180,
"height": 180
}
}
]
}
}
}Frontend Implementation
React / Next.js Example
Next.js with App Router
File: app/layout.tsx
import { Metadata } from 'next'
async function getSiteSettings() {
const response = await fetch(
`https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.CONTENTFUL_ACCESS_TOKEN}`,
},
body: JSON.stringify({
query: `
query {
siteSettingsCollection(limit: 1) {
items {
faviconIco { url }
favicon16 { url }
favicon32 { url }
appleTouchIcon { url }
}
}
}
`,
}),
}
)
const data = await response.json()
return data.data.siteSettingsCollection.items[0]
}
export async function generateMetadata(): Promise<Metadata> {
const settings = await getSiteSettings()
return {
icons: {
icon: [
{ url: `https:${settings.favicon16.url}`, sizes: '16x16', type: 'image/png' },
{ url: `https:${settings.favicon32.url}`, sizes: '32x32', type: 'image/png' },
{ url: `https:${settings.faviconIco.url}`, type: 'image/x-icon' },
],
apple: { url: `https:${settings.appleTouchIcon.url}`, sizes: '180x180' },
},
}
}
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}React with React Helmet
import { Helmet } from 'react-helmet'
import { useEffect, useState } from 'react'
function App() {
const [favicons, setFavicons] = useState(null)
useEffect(() => {
fetchFavicons().then(setFavicons)
}, [])
if (!favicons) return null
return (
<>
<Helmet>
<link rel="icon" type="image/x-icon" href={`https:${favicons.faviconIco.url}`} />
<link rel="icon" type="image/png" sizes="16x16" href={`https:${favicons.favicon16.url}`} />
<link rel="icon" type="image/png" sizes="32x32" href={`https:${favicons.favicon32.url}`} />
<link rel="apple-touch-icon" sizes="180x180" href={`https:${favicons.appleTouchIcon.url}`} />
</Helmet>
{/* Your app content */}
</>
)
}REST API Alternative
Content Delivery API
REST API Request
GET https://cdn.contentful.com/spaces/{SPACE_ID}/entries?content_type=siteSettings&include=2
Authorization: Bearer {ACCESS_TOKEN}JavaScript Example
const contentful = require('contentful')
const client = contentful.createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
})
async function getFavicons() {
const response = await client.getEntries({
content_type: 'siteSettings',
limit: 1,
})
const settings = response.items[0].fields
return {
faviconIco: `https:${settings.faviconIco.fields.file.url}`,
favicon16: `https:${settings.favicon16.fields.file.url}`,
favicon32: `https:${settings.favicon32.fields.file.url}`,
appleTouchIcon: `https:${settings.appleTouchIcon.fields.file.url}`,
}
}Contentful Favicon Best Practices
? Recommendations
- Use GraphQL for efficient queries
- Cache API responses in frontend
- Use Contentful CDN URLs (fast delivery)
- Organize favicons in dedicated folder
- Use environment variables for tokens
- Implement fallback favicons locally
- Leverage Contentful's image optimization
- Version assets for cache busting
? Common Mistakes
- Forgetting to publish assets
- Not using HTTPS protocol in URLs
- Hardcoding space IDs in client code
- Not caching API responses
- Missing fallback for API failures
- Not validating asset URLs
- Querying on every page load (no cache)
- Exposing API tokens in frontend
Generate Contentful-Ready Favicons
Create favicon packages optimized for headless CMS deployment
Generate Favicons