Default Theme: Carbon Ads
Learn how to integrate Carbon Ads with the VitePress default theme.
Overview
Carbon Ads is a privacy-focused ad network for developers and designers. VitePress provides built-in support for Carbon Ads integration.
Basic Setup
Configuration
Add Carbon Ads to your theme configuration:
// .vitepress/config.js
export default {
themeConfig: {
carbonAds: {
code: 'your-carbon-code',
placement: 'your-placement-id'
}
}
}
Getting Carbon Ads Credentials
- Sign up at Carbon Ads
- Create a new ad placement
- Get your
code
andplacement
values - Add them to your VitePress configuration
Configuration Options
Basic Configuration
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom'
}
}
}
Advanced Configuration
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom',
// Custom configuration
serve: 'CEBDT27Y',
format: 'cover',
// Targeting options
segment: 'placement:vitepressdevcom',
// Custom styling
className: 'custom-carbon-ads'
}
}
}
Placement Options
Sidebar Placement
Carbon Ads appear in the sidebar by default:
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom'
}
}
}
Custom Placement
Place ads in custom locations:
<!-- In your custom theme or component -->
<template>
<div class="custom-ad-container">
<CarbonAds
:code="carbonConfig.code"
:placement="carbonConfig.placement"
/>
</div>
</template>
<script setup>
import { useData } from 'vitepress'
const { theme } = useData()
const carbonConfig = theme.value.carbonAds
</script>
Multiple Placements
Use different placements for different pages:
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom',
// Page-specific placements
placements: {
'/guide/': 'vitepressguide',
'/api/': 'vitepressapi',
'/examples/': 'vitepressexamples'
}
}
}
}
Styling Carbon Ads
Default Styling
Carbon Ads come with default styling that matches the VitePress theme:
.carbon-ads {
display: block;
overflow: hidden;
max-width: 330px;
border-radius: 4px;
text-align: center;
border: 1px solid var(--vp-c-border);
background-color: var(--vp-c-bg-soft);
}
.carbon-img {
display: block;
margin: 0 auto;
line-height: 1;
}
.carbon-text {
display: block;
padding: 10px;
line-height: 1.35;
text-decoration: none;
color: var(--vp-c-text-1);
font-size: 12px;
}
.carbon-poweredby {
display: block;
padding: 6px 10px;
background: var(--vp-c-bg-mute);
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
font-size: 9px;
line-height: 1;
border-top: 1px solid var(--vp-c-border);
color: var(--vp-c-text-2);
}
Custom Styling
Customize the appearance:
/* Custom Carbon Ads styling */
.custom-carbon-ads {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease;
}
.custom-carbon-ads:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.custom-carbon-ads .carbon-text {
font-size: 13px;
line-height: 1.4;
padding: 12px;
}
.custom-carbon-ads .carbon-poweredby {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-size: 10px;
}
Responsive Design
Make ads responsive:
.carbon-ads {
width: 100%;
max-width: 330px;
}
@media (max-width: 768px) {
.carbon-ads {
max-width: 280px;
margin: 0 auto;
}
.carbon-text {
font-size: 11px;
padding: 8px;
}
}
@media (max-width: 480px) {
.carbon-ads {
max-width: 100%;
}
}
Advanced Integration
Conditional Display
Show ads conditionally:
<script setup>
import { computed } from 'vue'
import { useData } from 'vitepress'
const { page, theme } = useData()
const shouldShowAds = computed(() => {
// Don't show ads on certain pages
const excludedPaths = ['/privacy', '/terms', '/contact']
if (excludedPaths.includes(page.value.relativePath)) {
return false
}
// Only show ads in production
if (import.meta.env.DEV) {
return false
}
return theme.value.carbonAds?.code
})
</script>
<template>
<div v-if="shouldShowAds" class="carbon-ads-container">
<CarbonAds
:code="theme.carbonAds.code"
:placement="theme.carbonAds.placement"
/>
</div>
</template>
A/B Testing
Implement A/B testing for ad placements:
<script setup>
import { ref, onMounted } from 'vue'
import { useData } from 'vitepress'
const { theme } = useData()
const adVariant = ref('A')
onMounted(() => {
// Simple A/B testing
adVariant.value = Math.random() > 0.5 ? 'A' : 'B'
})
const adConfig = computed(() => {
const baseConfig = theme.value.carbonAds
if (adVariant.value === 'B') {
return {
...baseConfig,
placement: baseConfig.placementB || baseConfig.placement
}
}
return baseConfig
})
</script>
<template>
<CarbonAds
:code="adConfig.code"
:placement="adConfig.placement"
:data-variant="adVariant"
/>
</template>
Analytics Integration
Track ad performance:
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
// Track ad impressions
if (typeof gtag !== 'undefined') {
gtag('event', 'carbon_ad_impression', {
event_category: 'advertising',
event_label: 'carbon_ads'
})
}
// Track ad clicks
document.addEventListener('click', (event) => {
if (event.target.closest('.carbon-ads')) {
if (typeof gtag !== 'undefined') {
gtag('event', 'carbon_ad_click', {
event_category: 'advertising',
event_label: 'carbon_ads'
})
}
}
})
})
</script>
Custom Carbon Ads Component
Enhanced Component
Create a custom Carbon Ads component:
<!-- components/EnhancedCarbonAds.vue -->
<template>
<div
v-if="shouldShow"
class="enhanced-carbon-ads"
:class="{ 'is-loading': isLoading }"
>
<div v-if="isLoading" class="carbon-loading">
<div class="loading-skeleton"></div>
</div>
<div
ref="carbonContainer"
class="carbon-container"
:style="{ opacity: isLoading ? 0 : 1 }"
></div>
<div v-if="showLabel" class="carbon-label">
Advertisement
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
const props = defineProps({
code: {
type: String,
required: true
},
placement: {
type: String,
required: true
},
showLabel: {
type: Boolean,
default: true
},
lazy: {
type: Boolean,
default: false
}
})
const carbonContainer = ref(null)
const isLoading = ref(true)
const isVisible = ref(!props.lazy)
const shouldShow = computed(() => {
return props.code && props.placement && isVisible.value
})
let observer = null
onMounted(() => {
if (props.lazy) {
// Lazy load ads when they come into view
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
isVisible.value = true
observer.unobserve(entry.target)
}
})
},
{ threshold: 0.1 }
)
observer.observe(carbonContainer.value)
} else {
loadAd()
}
})
onUnmounted(() => {
if (observer) {
observer.disconnect()
}
})
function loadAd() {
if (!carbonContainer.value) return
// Create Carbon Ads script
const script = document.createElement('script')
script.src = `//cdn.carbonads.com/carbon.js?serve=${props.code}&placement=${props.placement}`
script.id = '_carbonads_js'
script.async = true
script.onload = () => {
isLoading.value = false
}
script.onerror = () => {
isLoading.value = false
console.warn('Failed to load Carbon Ads')
}
carbonContainer.value.appendChild(script)
}
// Watch for visibility changes
watch(isVisible, (visible) => {
if (visible && !isLoading.value) {
loadAd()
}
})
</script>
<style scoped>
.enhanced-carbon-ads {
position: relative;
margin: 20px 0;
}
.carbon-container {
transition: opacity 0.3s ease;
}
.carbon-loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
}
.loading-skeleton {
width: 330px;
height: 132px;
background: linear-gradient(
90deg,
var(--vp-c-bg-mute) 25%,
var(--vp-c-bg-soft) 50%,
var(--vp-c-bg-mute) 75%
);
background-size: 200% 100%;
animation: loading 1.5s infinite;
border-radius: 4px;
}
@keyframes loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.carbon-label {
text-align: center;
font-size: 10px;
color: var(--vp-c-text-3);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 8px;
}
.is-loading .carbon-label {
opacity: 0.5;
}
</style>
Privacy and Compliance
GDPR Compliance
Handle GDPR requirements:
<script setup>
import { ref, computed } from 'vue'
const hasConsent = ref(false)
const showConsentBanner = ref(true)
const shouldShowAds = computed(() => {
// Only show ads if user has consented
return hasConsent.value
})
function grantConsent() {
hasConsent.value = true
showConsentBanner.value = false
localStorage.setItem('carbon-ads-consent', 'true')
}
function denyConsent() {
hasConsent.value = false
showConsentBanner.value = false
localStorage.setItem('carbon-ads-consent', 'false')
}
onMounted(() => {
const consent = localStorage.getItem('carbon-ads-consent')
if (consent === 'true') {
hasConsent.value = true
showConsentBanner.value = false
} else if (consent === 'false') {
hasConsent.value = false
showConsentBanner.value = false
}
})
</script>
<template>
<div v-if="showConsentBanner" class="consent-banner">
<p>We use Carbon Ads to show relevant advertisements. Do you consent to personalized ads?</p>
<button @click="grantConsent">Accept</button>
<button @click="denyConsent">Decline</button>
</div>
<CarbonAds v-if="shouldShowAds" />
</template>
Do Not Track
Respect Do Not Track headers:
function shouldShowAds() {
// Check Do Not Track setting
if (navigator.doNotTrack === '1' ||
window.doNotTrack === '1' ||
navigator.msDoNotTrack === '1') {
return false
}
return true
}
Performance Optimization
Lazy Loading
Implement lazy loading for better performance:
<script setup>
import { ref, onMounted } from 'vue'
const adContainer = ref(null)
const isLoaded = ref(false)
onMounted(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !isLoaded.value) {
loadCarbonAds()
observer.unobserve(entry.target)
}
})
},
{ threshold: 0.1 }
)
if (adContainer.value) {
observer.observe(adContainer.value)
}
})
function loadCarbonAds() {
isLoaded.value = true
// Load Carbon Ads script
}
</script>
Preloading
Preload Carbon Ads resources:
<!-- In your HTML head -->
<link rel="dns-prefetch" href="//cdn.carbonads.com">
<link rel="preconnect" href="//cdn.carbonads.com">
Troubleshooting
Common Issues
Ads not showing:
- Check your code and placement values
- Verify your domain is approved by Carbon Ads
- Ensure you're not using ad blockers during testing
- Check browser console for errors
Styling issues:
- Check CSS specificity
- Verify CSS variables are defined
- Test in different browsers
- Check for conflicting styles
Performance issues:
- Implement lazy loading
- Use DNS prefetching
- Optimize CSS delivery
- Monitor Core Web Vitals
Debug Mode
Enable debug mode for troubleshooting:
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom',
debug: process.env.NODE_ENV === 'development'
}
}
}
Best Practices
User Experience
- Non-intrusive placement - Don't interfere with content
- Relevant ads - Use proper targeting
- Fast loading - Implement lazy loading
- Responsive design - Work on all devices
Performance
- Lazy loading - Load ads only when needed
- DNS prefetching - Preload Carbon Ads resources
- Minimal CSS - Keep styling lightweight
- Error handling - Gracefully handle loading failures
Privacy
- Respect user preferences - Honor Do Not Track
- GDPR compliance - Obtain proper consent
- Transparent disclosure - Clearly label advertisements
- Data minimization - Only collect necessary data
Maintenance
- Monitor performance - Track loading times and errors
- Update regularly - Keep Carbon Ads integration current
- Test thoroughly - Verify functionality across browsers
- Backup plans - Have fallbacks for ad failures
Examples
Basic Implementation
// .vitepress/config.js
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom'
}
}
}
Advanced Implementation
// .vitepress/config.js
export default {
themeConfig: {
carbonAds: {
code: 'CEBDT27Y',
placement: 'vitepressdevcom',
// Conditional display
enabled: process.env.NODE_ENV === 'production',
// Custom styling
className: 'custom-carbon-ads',
// Analytics
trackImpressions: true,
trackClicks: true,
// A/B testing
variants: {
A: { placement: 'vitepressdevcom' },
B: { placement: 'vitepressdevcom-alt' }
}
}
}
}
Custom Theme Integration
<!-- .vitepress/theme/components/CarbonAdsWrapper.vue -->
<template>
<div class="carbon-ads-wrapper">
<h4 class="ads-title">Sponsored</h4>
<CarbonAds
v-if="shouldShowAds"
:code="carbonConfig.code"
:placement="carbonConfig.placement"
@load="onAdLoad"
@error="onAdError"
/>
<div v-else class="ads-placeholder">
<p>Support us by disabling your ad blocker</p>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useData } from 'vitepress'
const { theme } = useData()
const carbonConfig = computed(() => theme.value.carbonAds || {})
const shouldShowAds = computed(() => {
return carbonConfig.value.code &&
carbonConfig.value.placement &&
!window.navigator.doNotTrack
})
function onAdLoad() {
console.log('Carbon ad loaded successfully')
}
function onAdError() {
console.warn('Failed to load Carbon ad')
}
</script>
<style scoped>
.carbon-ads-wrapper {
margin: 24px 0;
padding: 16px;
border: 1px solid var(--vp-c-border);
border-radius: 8px;
background: var(--vp-c-bg-soft);
}
.ads-title {
margin: 0 0 12px 0;
font-size: 12px;
font-weight: 500;
color: var(--vp-c-text-2);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.ads-placeholder {
text-align: center;
padding: 20px;
color: var(--vp-c-text-2);
font-size: 14px;
}
</style>
This completes the comprehensive guide for integrating Carbon Ads with VitePress, covering everything from basic setup to advanced customization and best practices.