Skip to content

Saved Templates Deep Dive

Create reusable template configurations for consistent branding.

Overview

Saved templates let you:

  • Store frequently used configurations
  • Maintain brand consistency
  • Reduce API payload size
  • Share settings across your team

Creating Templates

Via Dashboard

  1. Go to Dashboard → Templates
  2. Click "Create Template"
  3. Configure your settings
  4. Save with a unique ID

Via API

javascript
const response = await fetch('/api/user-templates', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({
    template_id: 'company-blog-dark',
    template_data: {
      template: 'blog',
      theme: 'dark',
      logo_url: 'https://mycompany.com/logo.png',
      author_avatar_url: 'https://mycompany.com/default-avatar.png'
    }
  })
});

Template Organization

Naming Conventions

Use descriptive, hierarchical IDs:

{purpose}-{variant}-{theme}

Examples:
- blog-standard-dark
- blog-featured-light
- product-sale-dark
- email-welcome-light

Categorization

Create templates for each use case:

CategoryTemplate IDs
Blogblog-default, blog-tutorial, blog-news
Productsproduct-standard, product-sale, product-new
Marketingsocial-announcement, social-milestone
Emailemail-welcome, email-receipt, email-newsletter

Template Inheritance

Merge saved templates with request-time parameters:

javascript
// Saved template
{
  template_id: 'blog-company',
  template_data: {
    template: 'blog',
    theme: 'dark',
    logo_url: 'https://company.com/logo.png'
  }
}

// Request
{
  user_template_id: 'blog-company',
  title: 'New Post Title',
  subtitle: 'Post description'
}

// Result: merged
{
  template: 'blog',
  theme: 'dark',
  logo_url: 'https://company.com/logo.png',
  title: 'New Post Title',
  subtitle: 'Post description'
}

Override Behavior

Request parameters override template settings:

javascript
// Template has theme: 'dark'
// Request has theme: 'light'
// Result: theme is 'light'

Implementation Patterns

Factory Pattern

javascript
class OGImageFactory {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.templates = new Map();
  }
  
  async loadTemplates() {
    const response = await fetch('/api/user-templates', {
      credentials: 'include'
    });
    const data = await response.json();
    
    for (const template of data.templates) {
      this.templates.set(template.template_id, template.template_data);
    }
  }
  
  async generate(templateId, overrides = {}) {
    const baseTemplate = this.templates.get(templateId);
    if (!baseTemplate) {
      throw new Error(`Template not found: ${templateId}`);
    }
    
    const params = { ...baseTemplate, ...overrides };
    
    return fetch('/api/generate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': this.apiKey
      },
      body: JSON.stringify(params)
    });
  }
}

// Usage
const factory = new OGImageFactory(apiKey);
await factory.loadTemplates();

const image = await factory.generate('blog-company', {
  title: 'My Post',
  subtitle: 'Description'
});

Template Service

javascript
// services/og-templates.js
class OGTemplateService {
  static TEMPLATES = {
    'blog-standard': {
      template: 'blog',
      theme: 'dark',
      logo_url: process.env.LOGO_URL
    },
    'blog-guest': {
      template: 'blog',
      theme: 'light'
    },
    'product-default': {
      template: 'product',
      theme: 'dark',
      logo_url: process.env.LOGO_URL
    },
    'product-sale': {
      template: 'product',
      theme: 'dark',
      badge: 'SALE',
      logo_url: process.env.LOGO_URL
    }
  };
  
  static getParams(templateId, overrides) {
    const base = this.TEMPLATES[templateId];
    if (!base) throw new Error(`Unknown template: ${templateId}`);
    return { ...base, ...overrides };
  }
}

Multi-Brand Support

For agencies or multi-tenant platforms:

javascript
const brandTemplates = {
  'brand-a': {
    'blog': {
      template: 'blog',
      theme: 'dark',
      logo_url: 'https://brand-a.com/logo.png'
    }
  },
  'brand-b': {
    'blog': {
      template: 'blog',
      theme: 'light',
      logo_url: 'https://brand-b.com/logo.png'
    }
  }
};

function getTemplate(brandId, templateType) {
  return brandTemplates[brandId]?.[templateType];
}

Versioning Templates

Track template changes over time:

javascript
const templates = {
  'blog-v1': { /* old config */ },
  'blog-v2': { /* new config */ }
};

// Or use date-based versions
const templates = {
  'blog-2024-01': { /* config */ },
  'blog-2024-06': { /* updated config */ }
};

Best Practices

  1. Use descriptive IDs — Clear naming helps organization
  2. Group by purpose — Blog, product, marketing, etc.
  3. Include brand assets — Logos, default avatars
  4. Version your templates — Track changes over time
  5. Document internally — Keep a template catalog
  6. Test before deploying — Preview each template

Template Limits

PlanMax Templates
Free5
Pro50
BusinessUnlimited

Migration Between Environments

Export templates for different environments:

javascript
// Export
const templates = await fetch('/api/user-templates', { credentials: 'include' })
  .then(r => r.json())
  .then(d => d.templates);

fs.writeFileSync('templates.json', JSON.stringify(templates, null, 2));

// Import
const templates = JSON.parse(fs.readFileSync('templates.json'));

for (const template of templates) {
  await fetch('/api/user-templates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'include',
    body: JSON.stringify({
      template_id: template.template_id,
      template_data: template.template_data
    })
  });
}

Generate stunning Open Graph images programmatically.