Substack

ニュースレター・有料購読特化のプラットフォーム。ライター向けの収益化機能が充実。

CMSニュースレター有料購読メール配信ポッドキャスト
ライセンス
Commercial
言語
Web Platform
料金
基本機能無料

CMS

Substack

概要

Substackは、ニュースレター・有料購読に特化したプラットフォームで、ライター向けの充実した収益化機能を提供します。

詳細

Substack(サブスタック)は、2017年に設立されたニュースレター配信とコンテンツ収益化に特化したプラットフォームです。「ライターファースト」の理念の下、独立したジャーナリストやクリエイターが読者と直接つながり、持続可能な収益を得られる仕組みを提供しています。

Substackの最大の特徴は、メール配信と有料購読の統合です。執筆したコンテンツは自動的にメールとして購読者に配信され、同時にウェブサイトにも公開されます。有料購読機能により、月額または年額でコンテンツを販売でき、収益の90%がライターに還元されます(Substackの手数料は10%)。

2024年現在、100万人以上のライターが活動し、2,000万人以上の有料購読者を抱えています。トップライターの中には年収50万ドル以上を稼ぐ者もいます。ポッドキャスト機能、コミュニティ機能(チャット、ディスカッション)、読者分析ツールなど、クリエイターエコノミーを支える機能が充実しています。

メリット・デメリット

メリット

  • 収益化に強い: 有料購読機能が標準搭載、手数料10%のみ
  • ニュースレター特化: メール配信の自動化と管理が簡単
  • 読者管理: 購読者リストの完全な所有権とエクスポート機能
  • 無料で開始: 基本機能は完全無料、有料購読時のみ手数料
  • ポッドキャスト対応: 音声コンテンツの配信も可能
  • コミュニティ機能: 読者との直接的な交流を促進
  • 分析機能: 詳細な読者分析とエンゲージメント指標

デメリット

  • プラットフォーム依存: Substackのインフラに完全依存
  • 手数料が高い: 10%の手数料は他のプラットフォームより高め
  • カスタマイズ制限: デザインやレイアウトの自由度が低い
  • 独自ドメイン制限: カスタムドメインは有料購読者のみ
  • API未提供: 公式APIがなく、外部連携が困難
  • SEO制限: 検索エンジン最適化の選択肢が限定的

主要リンク

使い方の例

基本的な埋め込みフォーム

<!-- Substackのデフォルト埋め込みフォーム -->
<!-- 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>

<!-- レスポンシブ対応版 -->
<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>

カスタマイズ可能な埋め込みフォーム(SubstackAPI使用)

// SubstackAPIを使ったカスタム埋め込みフォーム
// https://substackapi.com で生成

// 1. グローバル設定
window.CustomSubstackWidget = {
  substackUrl: "yourpublication.substack.com",
  placeholder: "メールアドレスを入力",
  buttonText: "購読する",
  theme: "custom",
  colors: {
    primary: "#FF6B6B",      // ボタンの背景色
    input: "#FFFFFF",        // 入力フィールドの背景色
    email: "#333333",        // メールテキストの色
    text: "#FFFFFF",         // ボタンテキストの色
  },
  // カスタムリダイレクト(有料プラン)
  redirectUrl: "https://yoursite.com/thank-you"
};

// 2. スクリプトの読み込み
const script = document.createElement('script');
script.src = "https://substackapi.com/widget.js";
script.async = true;
document.body.appendChild(script);

React/Next.jsでの統合

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

const SubstackWidget = ({ 
  substackUrl = "yourpublication.substack.com",
  theme = "custom",
  primaryColor = "#FF6B6B",
  buttonText = "ニュースレターを購読"
}) => {
  useEffect(() => {
    // ウィジェット設定
    window.CustomSubstackWidget = {
      substackUrl,
      placeholder: "メールアドレス",
      buttonText,
      theme,
      colors: {
        primary: primaryColor,
        input: "#FFFFFF",
        email: "#333333",
        text: "#FFFFFF",
      },
    };

    // スクリプトの動的読み込み
    const script = document.createElement('script');
    script.src = "https://substackapi.com/widget.js";
    script.async = true;
    document.body.appendChild(script);

    // クリーンアップ
    return () => {
      document.body.removeChild(script);
      delete window.CustomSubstackWidget;
    };
  }, [substackUrl, theme, primaryColor, buttonText]);

  return (
    <div id="custom-substack-embed" className="substack-widget-container">
      {/* ウィジェットがここにレンダリングされます */}
    </div>
  );
};

export default SubstackWidget;

WordPressでの統合

// functions.php に追加
function add_substack_widget_shortcode($atts) {
    $atts = shortcode_atts(array(
        'url' => 'yourpublication.substack.com',
        'button_text' => '購読する',
        '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: "メールアドレスを入力",
                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');

// 使用例: [substack_widget url="yourpublication.substack.com" button_text="今すぐ購読"]

RSSフィード活用

// SubstackのRSSフィードを取得して表示
async function fetchSubstackPosts(substackUrl) {
  const RSS_URL = `https://${substackUrl}/feed`;
  
  try {
    // Fetch API を使用(CORSの制限がある場合はプロキシサーバーが必要)
    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取得エラー:', error);
    return [];
  }
}

// 最新記事をウェブサイトに表示
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('ja-JP')}</time>
      <div class="excerpt">${post.content.substring(0, 200)}...</div>
      <a href="${post.link}" target="_blank" class="read-more">続きを読む →</a>
    </article>
  `).join('');
  
  container.innerHTML = postsHTML;
}

自動化とワークフロー

// Observable Notebookを使った半自動化(Simon Willison方式)
// ニュースレター生成の自動化例

// 1. データソースからコンテンツを取得
async function generateNewsletterContent() {
  // ブログ記事、ツイート、その他のソースからデータを収集
  const blogPosts = await fetchRecentBlogPosts();
  const tweets = await fetchPopularTweets();
  const links = await fetchCuratedLinks();
  
  // HTMLテンプレートを生成
  const newsletterHTML = `
    <h2>今週のハイライト</h2>
    
    <h3>最新ブログ記事</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>人気ツイート</h3>
    ${tweets.map(tweet => `
      <blockquote>
        <p>${tweet.text}</p>
        <cite>— ${tweet.date}</cite>
      </blockquote>
    `).join('')}
    
    <h3>今週のおすすめリンク</h3>
    <ul>
      ${links.map(link => `
        <li><a href="${link.url}">${link.title}</a> - ${link.description}</li>
      `).join('')}
    </ul>
  `;
  
  // クリップボードにコピー(手動でSubstackエディタに貼り付け)
  await navigator.clipboard.writeText(newsletterHTML);
  console.log('ニュースレターコンテンツをクリップボードにコピーしました');
}

// 2. 購読者分析ダッシュボード
function createAnalyticsDashboard(subscriberData) {
  // Chart.jsやD3.jsを使った視覚化
  const growthChart = new Chart(document.getElementById('growth-chart'), {
    type: 'line',
    data: {
      labels: subscriberData.dates,
      datasets: [{
        label: '購読者数',
        data: subscriberData.counts,
        borderColor: '#FF6B6B',
        tension: 0.1
      }]
    }
  });
  
  // 統計情報の表示
  const stats = {
    totalSubscribers: subscriberData.total,
    paidSubscribers: subscriberData.paid,
    conversionRate: (subscriberData.paid / subscriberData.total * 100).toFixed(2),
    monthlyRevenue: subscriberData.paid * 500 // 月額500円と仮定
  };
  
  document.getElementById('stats').innerHTML = `
    <div class="stat-card">
      <h4>総購読者数</h4>
      <p>${stats.totalSubscribers.toLocaleString()}</p>
    </div>
    <div class="stat-card">
      <h4>有料購読者</h4>
      <p>${stats.paidSubscribers.toLocaleString()}</p>
    </div>
    <div class="stat-card">
      <h4>コンバージョン率</h4>
      <p>${stats.conversionRate}%</p>
    </div>
    <div class="stat-card">
      <h4>月間収益</h4>
      <p>¥${stats.monthlyRevenue.toLocaleString()}</p>
    </div>
  `;
}