Vercel Integration

Connect your Vercel-hosted website to Blogree for automatic deployments. Whenever you publish, update, or delete a post in Blogree, your Vercel site will automatically rebuild and deploy the changes instantly.

Estimated setup time: 10 minutes


How It Works

Here's the flow when you publish a post in Blogree:

  1. You publish a post in Blogree Dashboard
  2. Blogree sends a webhook signal to your Vercel function
  3. Your Vercel function verifies the request is really from Blogree
  4. Your Vercel function triggers a deployment hook
  5. Vercel rebuilds your site with the new content
  6. Your website is live with the new post! ✅

Step 1: Create the Webhook Receiver Function

First, we need to create a Serverless Function in Vercel that receives webhooks from Blogree. This function will trigger your site to rebuild whenever content changes.

In the root of your project, create a folder named api (if you don't have one) and add a file named blogree.js.

api/blogree.js
/**
 * api/blogree.js
 * This Serverless Function receives Blogree webhooks and triggers Vercel rebuilds
 */
const crypto = require('crypto');
const https = require('https');
const http = require('http');

const WEBHOOK_SECRET = process.env.BLOGREE_WEBHOOK_SECRET;
const BUILD_HOOK_URL = process.env.BLOGREE_BUILD_HOOK_URL;

// Verify the webhook signature from Blogree
function verifySignature(rawBody, header) {
  if (!WEBHOOK_SECRET) {
    console.log('[Blogree] Warning: BLOGREE_WEBHOOK_SECRET not set');
    return true;
  }
  if (!header) {
    console.log('[Blogree] Error: Missing X-Blogree-Signature header');
    return false;
  }
  
  const expected = 'sha256=' + crypto.createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
  } catch (err) {
    console.log('[Blogree] Signature verification failed:', err.message);
    return false;
  }
}

// Trigger a Vercel deployment
function triggerBuild(postSlug) {
  return new Promise((resolve, reject) => {
    if (!BUILD_HOOK_URL) {
      console.log('[Blogree] Warning: BLOGREE_BUILD_HOOK_URL not set');
      return resolve();
    }

    console.log(`[Blogree] Triggering rebuild for post: ${postSlug}`);

    const url = new URL(BUILD_HOOK_URL);
    const req = (url.protocol === 'https:' ? https : http).request(
      {
        hostname: url.hostname,
        path: url.pathname + url.search,
        method: 'POST',
        headers: { 'Content-Length': 0 }
      },
      (res) => {
        console.log(`[Blogree] Vercel rebuild triggered — Status: ${res.statusCode}`);
        resolve();
      }
    );

    req.on('error', (err) => {
      console.log('[Blogree] Error triggering rebuild:', err.message);
      reject(err);
    });

    req.end();
  });
}

// Get raw body for signature verification
function rawBody(req) {
  return new Promise((resolve, reject) => {
    let data = '';
    req.on('data', (chunk) => (data += chunk));
    req.on('end', () => resolve(data));
    req.on('error', reject);
  });
}

// Main handler
module.exports = async (req, res) => {
  // Only accept POST requests
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    // Get the raw body for signature verification
    const body = await rawBody(req);
    const signature = req.headers['x-blogree-signature'] || '';

    // Verify the request is really from Blogree
    if (!verifySignature(body, signature)) {
      console.log('[Blogree] Invalid signature - rejecting request');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Parse the webhook payload
    let payload;
    try {
      payload = JSON.parse(body);
    } catch (err) {
      console.log('[Blogree] Invalid JSON payload');
      return res.status(400).json({ error: 'Invalid JSON' });
    }

    // Extract post information
    const postSlug = payload.post?.slug || 'unknown';
    const event = payload.event || 'unknown';

    console.log(`[Blogree] Received event: ${event} for post: ${postSlug}`);

    // Trigger the Vercel rebuild
    await triggerBuild(postSlug);

    return res.status(200).json({ success: true, message: 'Rebuild triggered' });
  } catch (err) {
    const errorMessage = err instanceof Error ? err.message : String(err);
    console.log('[Blogree] Error processing webhook:', errorMessage);
    return res.status(500).json({ error: errorMessage });
  }
};

Step 2: Create Your Vercel Configuration

Create a vercel.json file in your project root to configure your Serverless Function.

vercel.json
{
  "functions": {
    "api/blogree.js": {
      "memory": 128
    }
  }
}

Step 3: Create a Vercel Deploy Hook

Now we need to create a Deploy Hook in Vercel that your function can trigger to rebuild your site.

  1. Go to your Vercel Dashboard and select your project
  2. Navigate to SettingsGitDeploy Hooks
  3. Click Create Hook
  4. Name it Blogree
  5. Select your main branch (usually main or master)
  6. Click Create Hook
  7. Copy the generated URL (it will look like https://api.vercel.com/v1/integrations/deploy/abc...)

Step 4: Add Environment Variables to Vercel

Now we need to give Vercel the configuration it needs to connect to Blogree.

  1. In your Vercel project, go to SettingsEnvironment Variables
  2. Add the following environment variables:
bash
BLOGREE_WEBHOOK_SECRET=whs_your_secret_here
BLOGREE_BUILD_HOOK_URL=https://api.vercel.com/v1/integrations/deploy/abc...

Where to find each value:

  • BLOGREE_WEBHOOK_SECRET: Go to Blogree Dashboard → Sites → Your Site → Settings. Copy the Webhook Secret (starts with whs_)
  • BLOGREE_BUILD_HOOK_URL: Copy the Vercel Deploy Hook URL you created in Step 3

Step 5: Get Your Webhook URL

Your Vercel Serverless Function now has a public URL. It follows this pattern:

text
https://your-vercel-project.vercel.app/api/blogree

Replace your-vercel-project with your actual Vercel project name.

For example:

  • If your site is https://myblog.vercel.app, your webhook URL is:
    https://myblog.vercel.app/api/blogree
  • If you have a custom domain like https://myblog.com, your webhook URL is:
    https://myblog.com/api/blogree

Step 6: Connect Blogree to Vercel

Now tell Blogree where to send your webhook:

  1. Go to your Blogree Dashboard
  2. Go to Sites and select your Vercel site
  3. Go to Settings
  4. Find the Webhook URL field
  5. Paste your webhook URL (from Step 5)
  6. Make sure the Webhook Secret matches the environment variable you set in Vercel
  7. Click Save

Step 7: Test Your Integration

Let's verify everything is working:

  1. In Blogree, go to your site Settings
  2. Click Test Delivery or Test Webhook
  3. You should see a success message and a new deployment should start in Vercel

To verify the deployment:

  1. Go to your Vercel Dashboard
  2. Click on your project
  3. You should see a new deployment starting
  4. After 1-2 minutes, the deployment should be complete ✅

Step 8: Publish Your First Post

You're all set! Now let's test with a real post:

  1. In Blogree, create and publish a new post
  2. Wait 10-15 seconds for Vercel to rebuild
  3. Go to your website
  4. Your new post should appear! ✅

What Happens With Each Action

Publishing a Post

  • Blogree sends a webhook to your function
  • Your function verifies the signature
  • Your function triggers a Vercel deployment
  • Vercel rebuilds your site with the new post
  • Post appears on your website ✅

Updating a Post

  • Blogree sends an update webhook
  • Your function triggers a rebuild
  • Vercel rebuilds with the updated content
  • Changes appear on your website ✅

Deleting a Post

  • Blogree sends a deletion webhook
  • Your function triggers a rebuild
  • Vercel rebuilds without the deleted post
  • Post disappears from your website ✅

Troubleshooting

The test webhook fails with "Invalid signature"

Your BLOGREE_WEBHOOK_SECRET environment variable doesn't match the one in Blogree. Go back to Step 4 and verify they match exactly (including the whs_ prefix with no extra spaces).

The webhook succeeds but Vercel doesn't rebuild

Your BLOGREE_BUILD_HOOK_URL might be incorrect. Go back to your Vercel Deploy Hooks settings and copy the URL again, making sure there are no typos.

Posts aren't appearing on my site

Check that your Vercel build process properly fetches posts from Blogree. Make sure your build script is configured correctly in vercel.json.

I see deployment errors in Vercel

Check your build logs in Vercel Dashboard. The rebuild might be failing due to your build configuration or missing environment variables needed for your site.

Nothing is happening when I publish a post

Check these things:

  • Are both environment variables set in Vercel? (BLOGREE_WEBHOOK_SECRET and BLOGREE_BUILD_HOOK_URL)
  • Does your webhook URL match what's in Blogree Settings?
  • Try clicking "Test Webhook" in Blogree and check your Vercel function logs
  • Go to Vercel Dashboard → Your Project → View Function Logs to see what's happening