Dynamic Metadata through Cloudflare don't appear

I made the Cloudflare setup as per the tutorial, the worker seems to work (I see the requests made to it), but the dynamic metadata don’t appear on my page.

I’m using Baserow, the object contains the 4 elements required (among the other elements of the object), but the metadata are still the default ones of the website, or the default ones of the template page, instead of the ones through the Cloudflare Worker.

How to troubleshoot this further?
@Slavo @flo
.

Helo @pinshasa :wave:

Can you please make a screen recording describing the issue?

Hi @DanielL

Thanks for your message, here is the video Weweb Dynamic Metadata Issues 🔍

Hi @DanielL, would you be able to help our team as well?

JJ from our team posted this thread and Greg from our team posted this thread, but we still haven’t been able to resolve things.

Hi @DanielL & @flo ,

As discussed yesterday with @flo in the Office Hours, I’ve tried to access the Worker logs to see where is the issue (Weweb, or Baserow API call, or…), following their tutorial.
I added the configuration Cloudflare indicates in the wrangler.toml file of my Github repo, but nothing changed (still can’t see the logs).
I deployed the worker again, but nothing changed (still can’t see the logs).


Maybe you have an idea of why I still don’t see the logs (where was I wrong here) ?

Hi @pinshasa and @caffeinatedwes

Can you please create a ticket here so we can have a better look: https://support.weweb.io/?

We will also update our documentation on this.

ok, ticket sent !

1 Like

Hi @DanielL,

It’s been almost a month now, and still not a single follow up on this quite critical issue, whether in my ticket or here.
Any chance for it to be solved, or should I capitulate?

@pinshasa yeah there have been quite a few Cloudflare-related issues posted in the forum over the past couple months.

The most recent WeWeb update was about two weeks ago, stating that it would take a bit of time for them to come up with a solution but it’s being actively worked on.

3 Likes

Hi @pinshasa @ryanev

@Joyce will shed some light on this

4 Likes

Thanks @DanielL!

Hi @DanielL any update on this matter?

did anyone manage to make the dynamic metadata work recently?

I tried but failed a while ago and I am wondering if I could take a stab again.

hey @Jay12
I have a similar problem here, but i found that when i access the page without “www.”
the dynamic metatag will work

the worker only works on a custom domain without www.

can you try in your side and see if your worker also works without “www.” ?

I tried to redirect all www. to no www. but i will get a infinite redirect… i think it is some settings between weweb / cloudflare, @DanielL any idea?

1 Like

Hey @Jay12 ,
No news to my knowledge, unfortunately.

Couldn’t afford this absence of a solution after all the work put in it, so we just decided to migrate to another frontend for that app.

Apparently @chubao.uk found a beginning of workaround, so let’s hope the last mile of fix will be achieved soon!

Updates here:
I’ve been working around with Cloudflare settings and unable to access website without www. now…
the cloudflare worker can’t work in www. because we need to assign www. to weweb cname.

there are some solution by ChatGPT something like move www. behind cloudflare, not sure if it is possible for weweb.

i figured it out, it now works for me.

i’m using the cloudflare reverse proxy. i just followed the guide, even if some cloudflare UI was updated, it stays more or less the same. biggest struggles were:

  • figure out how to make it work with supabase
  • fix the pattern matching in the config to skip css and js files, or page load would break
  • use the cloudflare Routes to avoid touching the DNS

all the meta tags in the head are updated with dynamic content that is in my db, you can check the head source code of eg this page https://www.nomadretreats.co/experience/workation-in-tursi-italy-in-may-by-tursi-digital-nomads/

only one caveat. even if my reverse proxy updates the title tag, weweb dynamically overwrites it after page loads. i’ll try to open a bug or get more info on how to prevent this.

How to get it to work

Replace these lines of the original code

with something like this:

      // Fetch metadata from the API endpoint
      try {
        const metaDataResponse = await fetch(metaDataEndpointWithId, {
          method: 'POST',
          headers: {
            'Authorization': 'Bearer ' + env.SUPABASE_KEY, // Set this in the Cloudflare Worker settings
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ name: 'Functions' })
        });

        // Check if the response is valid JSON
        if (!metaDataResponse.ok) {
          console.error(`Error fetching metadata: ${metaDataResponse.status} ${metaDataResponse.statusText}`);
          const errorText = await metaDataResponse.text();
          console.error(`Response body: ${errorText}`);
          throw new Error(`Failed to fetch metadata: ${metaDataResponse.status}`);
        }

        return (await metaDataResponse.json());
      } catch (error) {
        console.error('Error in requestMetadata:', error);
        throw error;
      }
    }
    // END of async function requestMetadata(url, metaDataEndpoint)

Supabase Edge function

import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { createClient } from 'npm:@supabase/supabase-js@2';
Deno.serve(async (req)=>{
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, OPTIONS',
    'Access-Control-Allow-Headers': 'Authorization, Content-Type'
  };
  if (req.method === 'OPTIONS') {
    return new Response('ok', {
      headers: corsHeaders
    });
  }
  try {
    const url = new URL(req.url);
    // Remove any trailing slash from the URL
    const trimmedPath = url.pathname.endsWith('/') ? url.pathname.slice(0, -1) : url.pathname;
    // Extract the slug from the URL
    const slug = trimmedPath.split('/').pop();
    const supabase = createClient(Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_ANON_KEY') ?? '', {
      global: {
        headers: {
          Authorization: req.headers.get('Authorization')
        }
      }
    });
    const { data, error } = await supabase.from('your-meta-table').select('meta_title, meta_description, media_ids, tags').eq('slug', slug); // Query by slug
    if (error) {
      throw new Error(`Error fetching experience: ${error.message}`);
    }

// I have images in another table, used for the opengraph preview (not working yet)
    // Fetch media URLs based on media_id
    const mediaIds = data.flatMap((item)=>item.media_ids) || [];
    const { data: mediaData, error: mediaError } = await supabase.from('media').select('id, public_url').eq('id', mediaIds[0]);
    if (mediaError) {
      throw new Error(`Error fetching media: ${mediaError.message}`);
    }
    // Create a map of media IDs to URLs for easy lookup
    const mediaMap = Object.fromEntries(mediaData.map((item)=>[
        item.id,
        item.public_url
      ]));
    // Format the response to match the desired JSON structure
    const formattedData = data.map((item)=>({
        title: item.meta_title,
        description: item.meta_description,
        image: mediaMap[item.media_ids[0]],
        keywords: item.tags ? item.tags.join(", ") : ""
      }));
    // It's an array with one element, take first element
    return new Response(JSON.stringify(formattedData[0]), {
      headers: {
        'Content-Type': 'application/json',
        ...corsHeaders
      },
      status: 200
    });
  } catch (err) {
    return new Response(JSON.stringify({
      message: err.message
    }), {
      headers: {
        'Content-Type': 'application/json',
        ...corsHeaders
      },
      status: 500
    });
  }
});

Config file

i had to touch the config file compared to the one in the guide. the pattern with the starting ^ is matching only the right urls. this was critical to make it work for me or the worker would run on css and js files, breaking the whole page loading.

export const config = {
    domainSource: "https://your-preview-weweb-url-123456.weweb-preview.io", // Your WeWeb app preview link
    patterns: [
        {
            // the initial "^" is important to match only the page url, not its styles and scripts that share a similar url
            pattern: "^/provider/[^/]+",
            metaDataEndpoint: "https://your-supabase-url.supabase.co/functions/v1/getMetaProvider/{slug}"
        },
        {
            pattern: "^/experience/[^/]+",
            metaDataEndpoint: "https://your-supabase-url.supabase.co/functions/v1/getMetaExperience/{slug}"
        }
        // Add more patterns and their metadata endpoints as needed
    ]
};

DNS

you don’t need to add a dns like in the guide, a routes option is now available in the workers config. (there’s no reason why one has www and one *, i was just lazy)

my dns for the www (the only one i have) stays the same
image

3 Likes

@DanielL feel free to use my solution to update the docs. the new pattern matching and the Routes option were critical.

2 Likes

You are an absolute star! Thanks so much for taking the time to share this @vfede :grinning_face:

2 Likes

Hi @vfede , thanks for the clarification. Some days I’m trying to make it works.

Did you add your custom domain in Weweb and keep only the www DNS given ? (because only seeing “cloudfront”). Or your screenshot is a personal random target called cloudfront ?

For those feeling as lost as I was:

I attempted to follow the WeWeb documentation on dynamic metadata. Unfortunately, it doesn’t mention that the information is outdated. There’s an update available, but it’s outdated as well!

Next, I tried the AI support recommendation by “Wiera,” which suggested: “Remove your custom domain from WeWeb domain settings.” That approach didn’t work either.

Finally, I followed @vfede’s recommendation, and it worked. The missing part was to add the custom domain into WeWeb too.


Random information: Yesterday, my root domain (without www) was working with dynamic data active too. It just stops I don’t know why. I did so much retries, than I’m not feeling able to reproduce the same result, not even sure that is possible, I’m not a specialist.