Custom Domain Setup

How to Connect a Custom Domain to Your Marketplace

Learn how to use your own URL for your Prometora marketplace. This guide walks you through the steps of connecting your custom domain using Cloudflare.

Note: A custom domain is not required. Prometora provides a branded domain (prometora.com/s/your-store) that you can use as long as you want.

How a Custom Domain Works

You connect your custom domain to your Prometora marketplace by adding Domain Name System (DNS) records through Cloudflare and creating a Cloudflare Worker to route traffic to your store.

Prometora does not host your domain or offer domain hosting services. You should use domain registrars like GoDaddy, Namecheap, or Google Domains to purchase your domain. Then, you'll transfer DNS management to Cloudflare (free) and configure it to point to your Prometora marketplace.

Overview: Steps to Add Your Custom Domain

Here are the overall steps for adding your custom domain to your marketplace:

  1. Transfer DNS management to Cloudflare (one-time setup)
  2. Create a Cloudflare Worker
  3. Configure the Worker with routing code and environment variable
  4. Add your custom domain to the Worker (automatically creates DNS routing)
  5. Optional: Set up apex domain redirect and enable Always Use HTTPS
  6. Verify your domain in Prometora dashboard

Step 1: Transfer DNS to Cloudflare

First, you need to transfer DNS management to Cloudflare. This is a one-time setup that gives you access to free SSL certificates and a global CDN.

  1. Create a free account at Cloudflare
  2. Click "Add a Site" and enter your domain (e.g., example.com)
  3. Choose the Free plan
  4. Cloudflare will scan your existing DNS records
  5. Review the imported records (keep MX records for email!)
  6. Cloudflare will provide you with 2 nameservers (e.g., eva.ns.cloudflare.com and piotr.ns.cloudflare.com)
  7. Go to your domain registrar (Namecheap, GoDaddy, etc.)
  8. Find the nameservers section in your domain settings
  9. Replace the existing nameservers with Cloudflare's nameservers
  10. Save changes and wait 5-30 minutes for propagation

Important for email users: If you use email with your domain (like info@example.com), make sure your MX records are preserved in Cloudflare. Set mail-related A records to DNS only (grey cloud), not Proxied.

Step 2: Create a Cloudflare Worker

Cloudflare Workers allow you to route your custom domain to your Prometora marketplace.

  1. In Cloudflare, go to Workers & Pages (left sidebar)
  2. Click "Create Application"
  3. Click "Create Worker"
  4. Give it a name (e.g., "domain-proxy" or "marketplace-router")
  5. Click "Deploy"

Step 3: Configure Worker Code

The Worker needs the routing logic to look up your store and proxy requests to Prometora's servers.

  1. In your Worker, click "Edit Code" or "Quick Edit"
  2. Replace ALL code with the full routing code below
  3. Go to Settings → Variables and add environment variable:
    • Name: VERCEL_DEPLOYMENT_URL
    • Value: https://www.prometora.com
  4. Click "Save and Deploy"

Important: Use the complete code below. The Worker needs to look up which store owns your domain and route requests accordingly.

/**
 * Cloudflare Worker for Custom Domain Routing
 */

// Your Vercel deployment URL
const VERCEL_URL = typeof VERCEL_DEPLOYMENT_URL !== 'undefined' ? VERCEL_DEPLOYMENT_URL : 'https://www.prometora.com';
const API_BASE_URL = `${VERCEL_URL}/api`;

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const url = new URL(request.url);
  const hostname = url.hostname;

  // Skip for workers.dev domain (use for testing)
  if (hostname.endsWith('.workers.dev')) {
    return new Response('Cloudflare Worker is running! This is used for custom domain routing.', {
      headers: { 'content-type': 'text/plain' }
    });
  }

  try {
    // Check if this is a static asset request
    const isStaticAsset = url.pathname.startsWith('/_next/') ||
                          url.pathname.startsWith('/static/') ||
                          url.pathname.startsWith('/favicon.ico') ||
                          url.pathname.startsWith('/images/') ||
                          url.pathname.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/);

    // Check if this is an API request
    const isApiRequest = url.pathname.startsWith('/api/');

    // For static assets or API requests, proxy directly WITHOUT rewriting path
    if (isStaticAsset || isApiRequest) {
      const newUrl = new URL(request.url);
      newUrl.hostname = new URL(VERCEL_URL).hostname;
      newUrl.protocol = 'https:';
      // Keep original pathname for API routes and static assets

      const headers = new Headers(request.headers);

      // For API requests, add the custom domain header so middleware knows which store
      if (isApiRequest) {
        headers.set('X-Custom-Domain', hostname);
      }

      const modifiedRequest = new Request(newUrl.toString(), {
        method: request.method,
        headers: headers,
        body: request.body,
        redirect: 'follow'
      });

      return await fetch(modifiedRequest);
    }

    // Step 1: Look up which store owns this domain (only for non-API requests)
    const storeSlug = await getStoreByDomain(hostname);

    if (!storeSlug) {
      return new Response('Store not found for this domain', {
        status: 404,
        headers: { 'content-type': 'text/plain' }
      });
    }

    // Step 2: Rewrite URL to custom-domain path on Vercel (not /s/${storeSlug})
    const newUrl = new URL(request.url);
    newUrl.hostname = new URL(VERCEL_URL).hostname;
    newUrl.protocol = 'https:';
    // Use /custom-domain path instead of /s/${storeSlug}
    if (url.pathname === '/') {
      newUrl.pathname = `/custom-domain`;
    } else {
      newUrl.pathname = `/custom-domain${url.pathname}`;
    }

    // Step 3: Create modified request
    const modifiedRequest = new Request(newUrl.toString(), {
      method: request.method,
      headers: request.headers,
      body: request.body,
      redirect: 'follow'
    });

    // Add custom headers
    const headers = new Headers(modifiedRequest.headers);
    headers.set('X-Custom-Domain', hostname);
    headers.set('X-Store-Slug', storeSlug);
    headers.set('X-Forwarded-Host', hostname);

    const finalRequest = new Request(modifiedRequest, { headers });

    // Step 4: Fetch and return response
    const response = await fetch(finalRequest);
    const modifiedResponse = new Response(response.body, response);
    modifiedResponse.headers.set('X-Served-By', 'Cloudflare-Worker');

    // Handle redirects
    if (modifiedResponse.headers.has('location')) {
      let location = modifiedResponse.headers.get('location');
      if (location.includes(VERCEL_URL)) {
        location = location.replace(VERCEL_URL, `https://${hostname}`);
        location = location.replace(`/custom-domain`, '');
        modifiedResponse.headers.set('location', location);
      }
    }

    return modifiedResponse;

  } catch (error) {
    console.error('Worker error:', error);
    return new Response(`Error: ${error.message}`, {
      status: 500,
      headers: { 'content-type': 'text/plain' }
    });
  }
}

async function getStoreByDomain(domain) {
  try {
    const response = await fetch(`${API_BASE_URL}/stores/lookup?domain=${encodeURIComponent(domain)}`, {
      headers: {
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      console.error('Store lookup failed:', response.status);
      return null;
    }

    const data = await response.json();
    return data.slug || null;

  } catch (error) {
    console.error('Error looking up store:', error);
    return null;
  }
}

Step 4: Add Custom Domain to Worker

After configuring the Worker code, attach your custom domain to it. This automatically creates the necessary DNS routing.

  1. In your Worker, go to Settings → Domains & Routes
  2. Click "Add Custom Domain"
  3. Enter your domain: www.example.com
  4. Click "Add Domain"
  5. Cloudflare will automatically create DNS routing and provision an SSL certificate (1-2 minutes)

Note: When you add a custom domain to a Worker, Cloudflare automatically creates the necessary DNS records. You don't need to manually add CNAME records.

Step 5: Set up Apex Domain Redirect (Optional but Recommended)

If you're using www.example.com, you should redirect the apex domain (example.com) to www for consistency.

  1. In Cloudflare, go to DNS → Records
  2. Add an A record:
    • Type: A
    • Name: @ (represents apex domain)
    • IPv4 address: 192.0.2.1 (placeholder IP)
    • Proxy status: Proxied (orange cloud ☁️)
  3. Go to Rules → Redirect Rules
  4. Click "Create rule" and use the "Redirect from root to WWW" template
  5. Configure: Redirect https://example.com/* to https://www.example.com/$1
  6. Status code: 301 (permanent redirect)
  7. Enable SSL/TLS → Always Use HTTPS in Cloudflare settings

Step 6: Verify in Prometora Dashboard

The final step is to verify your domain in your Prometora store settings.

  1. Log in to your Prometora dashboard
  2. Go to Store Settings → Custom Domain
  3. Enter your custom domain (e.g., www.example.com)
  4. Click "Add Custom Domain"
  5. Wait 30 seconds, then click "Verify DNS"
  6. Your domain should now show as "Verified"

Success! Your marketplace is now live at your custom domain with automatic SSL encryption. Visit https://www.example.com to see your store.

Using a Subdomain

You can host your marketplace at a subdomain like shop.example.com, marketplace.example.com, or store.example.com.

The process is the same - just use your chosen subdomain (e.g., shop.example.com) when adding the custom domain to the Worker in Step 4.

Troubleshooting

Domain shows "Pending verification"?

  • Wait 1-2 minutes for DNS propagation
  • Verify the Worker code is deployed with the full routing logic
  • Make sure the custom domain is added to the Worker in Settings → Domains & Routes
  • Check that environment variable VERCEL_DEPLOYMENT_URL is set
  • Visit your domain directly in browser to see if it loads (even if verification pending)

Seeing "Cloudflare Worker is running!" message?

  • Make sure you deployed the full Worker code, not the simple proxy version
  • Check that you added the custom domain to the Worker (not just DNS)
  • Verify domain in Prometora dashboard so the platform knows about it

Email stopped working?

  • Check your MX records are still present in Cloudflare DNS
  • Verify mail-related A records are set to "DNS only" (grey cloud), not Proxied
  • SPF and DKIM records should also be preserved as TXT records

SSL certificate error?

  • Wait 5-10 minutes for Cloudflare to provision the certificate
  • Verify your domain is added to the Worker (Settings → Domains & Routes)
  • Ensure "Always Use HTTPS" is enabled in SSL/TLS settings

Need Help?

If you encounter issues or have questions about connecting your custom domain, please contact our support team at rasmus@speedbuildmarketplace.com. Include a screenshot of your DNS settings if you're unsure about your configuration.

How to Connect a Custom Domain | Prometora