Substack

Platform specialized in newsletters and paid subscriptions. Rich monetization features for writers.

CMSNewsletterPaid SubscriptionEmail DistributionPodcast
License
Commercial
Language
Web Platform
Pricing
基本機能無料
Official Site
Visit Official Site

CMS

Substack

Overview

Substack is a platform specialized in newsletters and paid subscriptions, offering rich monetization features for writers.

Details

Substack is a platform founded in 2017 specializing in newsletter distribution and content monetization. Under the "writer-first" philosophy, it provides a system where independent journalists and creators can connect directly with readers and earn sustainable revenue.

Substack's greatest feature is the integration of email distribution and paid subscriptions. Written content is automatically delivered to subscribers via email and simultaneously published on the website. With paid subscription functionality, content can be sold monthly or annually, with 90% of revenue going to writers (Substack's fee is 10%).

As of 2024, over 1 million writers are active with more than 20 million paid subscribers. Some top writers earn over $500,000 annually. It has rich features supporting the creator economy, including podcast functionality, community features (chat, discussions), and reader analytics tools.

Pros and Cons

Pros

  • Strong monetization: Built-in paid subscription, only 10% fee
  • Newsletter-focused: Easy email distribution automation and management
  • Reader management: Complete ownership and export of subscriber lists
  • Free to start: Basic features completely free, fees only on paid subscriptions
  • Podcast support: Audio content distribution available
  • Community features: Promotes direct interaction with readers
  • Analytics: Detailed reader analytics and engagement metrics

Cons

  • Platform dependency: Complete dependence on Substack infrastructure
  • High fees: 10% fee higher than other platforms
  • Customization limits: Low flexibility in design and layout
  • Custom domain limits: Custom domains only for paid subscribers
  • No API: No official API, difficult external integration
  • SEO limitations: Limited search engine optimization options

Key Links

Usage Examples

Basic Embed Form

<!-- Default Substack embed form -->
<!-- Get from Settings → Growth features -->
<iframe src="https://yourpublication.substack.com/embed" 
        width="480" 
        height="320" 
        style="border:1px solid #EEE; background:white;" 
        frameborder="0" 
        scrolling="no">
</iframe>

<!-- Responsive version -->
<div style="max-width: 100%; width: 480px;">
  <iframe src="https://yourpublication.substack.com/embed"
          style="border:1px solid #EEE; background:white; width: 100%;"
          frameborder="0"
          scrolling="no">
  </iframe>
</div>

Customizable Embed Form (Using SubstackAPI)

// Custom embed form using SubstackAPI
// Generate at https://substackapi.com

// 1. Global configuration
window.CustomSubstackWidget = {
  substackUrl: "yourpublication.substack.com",
  placeholder: "Enter your email",
  buttonText: "Subscribe",
  theme: "custom",
  colors: {
    primary: "#FF6B6B",      // Button background color
    input: "#FFFFFF",        // Input field background
    email: "#333333",        // Email text color
    text: "#FFFFFF",         // Button text color
  },
  // Custom redirect (paid plan)
  redirectUrl: "https://yoursite.com/thank-you"
};

// 2. Load script
const script = document.createElement('script');
script.src = "https://substackapi.com/widget.js";
script.async = true;
document.body.appendChild(script);

React/Next.js Integration

// components/SubstackWidget.jsx
import { useEffect } from 'react';

const SubstackWidget = ({ 
  substackUrl = "yourpublication.substack.com",
  theme = "custom",
  primaryColor = "#FF6B6B",
  buttonText = "Subscribe to Newsletter"
}) => {
  useEffect(() => {
    // Widget configuration
    window.CustomSubstackWidget = {
      substackUrl,
      placeholder: "Email address",
      buttonText,
      theme,
      colors: {
        primary: primaryColor,
        input: "#FFFFFF",
        email: "#333333",
        text: "#FFFFFF",
      },
    };

    // Dynamic script loading
    const script = document.createElement('script');
    script.src = "https://substackapi.com/widget.js";
    script.async = true;
    document.body.appendChild(script);

    // Cleanup
    return () => {
      document.body.removeChild(script);
      delete window.CustomSubstackWidget;
    };
  }, [substackUrl, theme, primaryColor, buttonText]);

  return (
    <div id="custom-substack-embed" className="substack-widget-container">
      {/* Widget renders here */}
    </div>
  );
};

export default SubstackWidget;

WordPress Integration

// Add to functions.php
function add_substack_widget_shortcode($atts) {
    $atts = shortcode_atts(array(
        'url' => 'yourpublication.substack.com',
        'button_text' => 'Subscribe',
        'primary_color' => '#FF6B6B',
        'width' => '100%',
        'max_width' => '480px'
    ), $atts);

    $widget_id = 'substack-widget-' . uniqid();

    $output = '
    <div id="' . $widget_id . '" style="width: ' . $atts['width'] . '; max-width: ' . $atts['max_width'] . ';">
        <script>
            window.CustomSubstackWidget = {
                substackUrl: "' . $atts['url'] . '",
                placeholder: "Enter email address",
                buttonText: "' . $atts['button_text'] . '",
                theme: "custom",
                colors: {
                    primary: "' . $atts['primary_color'] . '",
                    input: "#FFFFFF",
                    email: "#333333",
                    text: "#FFFFFF"
                }
            };
        </script>
        <script src="https://substackapi.com/widget.js" async></script>
    </div>';

    return $output;
}
add_shortcode('substack_widget', 'add_substack_widget_shortcode');

// Usage: [substack_widget url="yourpublication.substack.com" button_text="Subscribe Now"]

RSS Feed Utilization

// Fetch and display Substack RSS feed
async function fetchSubstackPosts(substackUrl) {
  const RSS_URL = `https://${substackUrl}/feed`;
  
  try {
    // Using Fetch API (proxy server needed if CORS restrictions)
    const response = await fetch(`https://api.rss2json.com/v1/api.json?rss_url=${RSS_URL}`);
    const data = await response.json();
    
    if (data.status === 'ok') {
      return data.items.map(item => ({
        title: item.title,
        link: item.link,
        pubDate: item.pubDate,
        author: item.author,
        content: item.content,
        thumbnail: item.thumbnail,
        categories: item.categories
      }));
    }
  } catch (error) {
    console.error('RSS fetch error:', error);
    return [];
  }
}

// Display latest posts on website
async function displayLatestPosts() {
  const posts = await fetchSubstackPosts('yourpublication.substack.com');
  const container = document.getElementById('substack-posts');
  
  const postsHTML = posts.slice(0, 5).map(post => `
    <article class="substack-post">
      ${post.thumbnail ? `<img src="${post.thumbnail}" alt="${post.title}">` : ''}
      <h3><a href="${post.link}" target="_blank">${post.title}</a></h3>
      <time>${new Date(post.pubDate).toLocaleDateString('en-US')}</time>
      <div class="excerpt">${post.content.substring(0, 200)}...</div>
      <a href="${post.link}" target="_blank" class="read-more">Read more →</a>
    </article>
  `).join('');
  
  container.innerHTML = postsHTML;
}

Automation and Workflows

// Semi-automation using Observable Notebook (Simon Willison approach)
// Newsletter generation automation example

// 1. Fetch content from data sources
async function generateNewsletterContent() {
  // Collect data from blog posts, tweets, and other sources
  const blogPosts = await fetchRecentBlogPosts();
  const tweets = await fetchPopularTweets();
  const links = await fetchCuratedLinks();
  
  // Generate HTML template
  const newsletterHTML = `
    <h2>This Week's Highlights</h2>
    
    <h3>Latest Blog Posts</h3>
    ${blogPosts.map(post => `
      <div style="margin-bottom: 20px;">
        <h4><a href="${post.url}">${post.title}</a></h4>
        <p>${post.excerpt}</p>
      </div>
    `).join('')}
    
    <h3>Popular Tweets</h3>
    ${tweets.map(tweet => `
      <blockquote>
        <p>${tweet.text}</p>
        <cite>— ${tweet.date}</cite>
      </blockquote>
    `).join('')}
    
    <h3>Recommended Links This Week</h3>
    <ul>
      ${links.map(link => `
        <li><a href="${link.url}">${link.title}</a> - ${link.description}</li>
      `).join('')}
    </ul>
  `;
  
  // Copy to clipboard (manually paste into Substack editor)
  await navigator.clipboard.writeText(newsletterHTML);
  console.log('Newsletter content copied to clipboard');
}

// 2. Subscriber analytics dashboard
function createAnalyticsDashboard(subscriberData) {
  // Visualization using Chart.js or D3.js
  const growthChart = new Chart(document.getElementById('growth-chart'), {
    type: 'line',
    data: {
      labels: subscriberData.dates,
      datasets: [{
        label: 'Subscribers',
        data: subscriberData.counts,
        borderColor: '#FF6B6B',
        tension: 0.1
      }]
    }
  });
  
  // Display statistics
  const stats = {
    totalSubscribers: subscriberData.total,
    paidSubscribers: subscriberData.paid,
    conversionRate: (subscriberData.paid / subscriberData.total * 100).toFixed(2),
    monthlyRevenue: subscriberData.paid * 5 // Assuming $5/month
  };
  
  document.getElementById('stats').innerHTML = `
    <div class="stat-card">
      <h4>Total Subscribers</h4>
      <p>${stats.totalSubscribers.toLocaleString()}</p>
    </div>
    <div class="stat-card">
      <h4>Paid Subscribers</h4>
      <p>${stats.paidSubscribers.toLocaleString()}</p>
    </div>
    <div class="stat-card">
      <h4>Conversion Rate</h4>
      <p>${stats.conversionRate}%</p>
    </div>
    <div class="stat-card">
      <h4>Monthly Revenue</h4>
      <p>$${stats.monthlyRevenue.toLocaleString()}</p>
    </div>
  `;
}