Custom BeeHiiv Home Page with Cloudflare
Tags: cloudflare, beehiiv, dns, http
Published: 2023-08-15 11:00:43

Before I migrated from Ghost to BeeHiiv, I wanted to keep my newsletter's [landing page](https://unzip.dev/), it got me around 1.5k subs from HN because it was unique - so I knew I need to keep it.

To achieve this I managed to use Cloudfalre, and here is how you can too.

Basically, we will create a subdomain for the landing page:
- unzip.dev/ → join.unzip.dev - my new home page.
- unzip.dev/* - my main website for the newsletter (on BeeHiiv).

This tutorial assumes you also want to use your root domain on BeeHiiv instead of www.yourdomain.com

## Step 1 - Connect your domain to BeeHiiv.
1. First I added my domain unzip.dev.
2. After verifying, add it to the Web Domain section.

## Step 2 - Open a Cloudflare account
1. Register to [Cloudflare](https://cloudflare.com/) move your registrar's DNS Nameservers to CloudFlare.

## Step 3 - Deploy your new home page
I used vercel.com and next.js. For that I added a CNAME to [vercel ](https://vercel.com) for join.unzip.dev.

## Step 4 - Patching CLoudflare
We want to hijack the requests to the root path. For that I had to add the following Cloudflare rules:
![Cloudflare rules](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwsn7wqf769bei4jkv7v.png)

1. For the archive page I had in Ghost (optional).
2. For the posts, in Ghost there are at: unzip.dev/[slug] on BeeHiiv they are at unzip.dev/p/[slug].
3. For the homepage I added a redirect from `/` to `join.unzip.dev` (on vercel).

## Bonus www -> root
To redirect all www. to root you have to add the following record:
- Add the following bulk redirects:

![WWW cloudflare rules](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrlg99es3uxl4q552vz0.png)

- `AAAA` for `www` with the value `100::` otherwise cloudflare will not run the bulk rules.

## API for landing page
To be able to subscribe people via my external landing page, I've added a cloudflare worker as follows:
```

export default {
  async fetch(request, env, ctx) {

    // Allow everyone to post to here via CORS
    const corsHeaders = {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "POST",
      "Access-Control-Allow-Headers": 'Content-Type'
    };

    // A hack to fix the OPTIONS response for CORS
    if (request.method === "OPTIONS") {
      // Handle CORS preflight requests
      return new Response(null, {
        headers: {...corsHeaders}
      })
    }


    const publicationId = 'pub_YOUR_PUBLICATION_ID';

    // Extract the subscription details from the request body
    const requestBody = await request.json();
    const { email } = requestBody;

      // Create the subscription
      const response = await fetch(`https://api.beehiiv.com/v2/publications/${publicationId}/subscriptions`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${env.BEEHIIV_KEY}`, // Replace with your actual bearer token
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          email,
          reactivate_existing: true,
          send_welcome_email: true, // Always send the welcome email
          utm_source: 'join.unzip.dev', 
          utm_medium: 'web',
          referring_site: 'join.unzip.dev', 
        }),
      });
  
      if (!response.ok) {
        throw new Error('Failed to create subscription');
      }

    return new Response("Subbe", {
        headers: {
          ...corsHeaders,
        },
      });
    }
};

```


At this point every time someone visits `/` they will be 301ed to join.unzip.dev (seeing my amazing landing page). Otherwise, they will be redirected to BeeHiiv to see the posts themselves.


I hope this helps other's that want to customize their BeeHiiv landing page.