Do I need a dynamic preview URL?

Hey folks!

Really confused on this one. Scoured the docs for a few hours and asked on the Discord, but alas. I’m getting some weird behavior in my project and not sure if I’m using the preview URL right. It seems to work, but only sort of. Should I be using a dynamic one?

Read on for the juicy details.

Builder content link

Builder public api key
add3bfefbde24699aeb53c5a1ad64377

What are you trying to accomplish
I’m writing a tutorial for integrating Builder with Astro. As a demo project for the tutorial I’m setting up a basic blog.

Project details:

  • The blog uses a section model for each blog post, as per the Builder docs.
  • It uses the REST API and no client-side JavaScript :metal:
  • A webhook triggers a rebuild when I change content on Builder.

I have two things nagging me:

  1. As it is now, I’m using a static preview URL and everything works already… kind of. There is a weird delay between changing the content on Builder and the content showing up. Sometimes I need to rebuild a few times. It’s weird. (See video below)

  2. After scouring the docs and forums for a few hours, I still don’t understand the benefits and/or necessities of a dynamic preview URL. When is it useful? When is it necessary? Why should I use a dynamic one if a static one works already? It’s hard not to get obsessed with this, as the docs suggest that using it for a URL model like mysite.xyz/.../${slug_to_a_blog_post} is a prime use case - This is me! I just don’t understand what this would get me.

My goals:

  1. Build a static blog where the content updates reliably after making a change (see point 1 above)
  2. Understand a little better when and why somebody would use a dynamic preview URL. I wanna make an informed decision which one to use here. If both are possible, I wanna give learners a brief rundown of the PROs and CONs of each in the tutorial.

These two things might be related, and I might be misunderstanding something fundamental :slight_smile:
Would love any input on this one. :heart:

PS. how do you make a dynamic preview URL static again? The field is greyed out and I can only click on the <> code editor button. I’m currently working around this by simply returning a static URL there.

Screenshots or video link
Video demo of content sometimes updating… but not always:

… but later, when I ran the dev server and built the site the correct content appeared - up to date and all!

Code stack you are integrating Builder with

  • Astro as my SSG
  • Builder’s REST API: The blog is static with no client-side JavaScript. My content and pre-rendered HTML gets fetched via Builder’s REST API at build time. The only<builder-component> is on my preview page.
  • Deploy on Netlify: The site gets rebuilt using a webhook when making a change in the visual editor.

Reproducible code example
Repo on gitpod

hi @habbeda apologies for delay here! Could you share a snippet of your code how you are integrating these blog pages to Builder?

As for the preview URL, and when to use a dynamic URL…there could be any number of reasons to use a dynamic URL, particularly if you are using templatized pages with content that is based on a slug… so in the instance you shared a blog is often a great use case for this!

Keep in mind, this logic is only for the preview URL in the builder editor, it doesn’t directly write the url of the live page. Generally, the url should match, but how the url is generated and routing is set would be handled in your app and then the preview url should point to where your content in your app will eventually live.

By using a dynamic URL you can templatize the blog page so that you don’t have to create a builder entry for every single page, you can just preview each entry based on the slug. You might find this forum post helpful: Using Advanced Editing URL Logic to set up dynamic preview URLs

Let me know if this helps clarify, happy to provide some examples if that is helpful, and please share any snippets to take a look at why your code migth bedelayed!

1 Like

Hey Tim!

Thanks for the reply. Everything in it’s own time :upside_down_face:

So, about the weird behavior where the site sometimes updated, sometimes not:
It seems to be fixed after adding cachebust=true to the API request. Thank You Builder Discord for the tip!

For reference and future people, my code looks now something like this:

// [...slug].astro
// represents a single blog post

// fetch all slugs available
// within getStaticPaths()
const { results: posts } = await fetch(
        `https://cdn.builder.io/api/v2/content/${builderModel}?${new URLSearchParams(
            {
                apiKey: builderAPIpublicKey,
                fields: "data.slug",
                cachebust: "true", 
}
)}`
})
// ...fetch error handling, etc...

// fetch content for each individual slug
// outside of getStaticPaths()
const { html: postHTML } = await fetch(
    `https://cdn.builder.io/api/v1/qwik/${builderModel}?${new URLSearchParams({
        apiKey: builderAPIpublicKey,
        url: encodedUrl,
        "query.data.slug": slug,
        cachebust: "true",
})}`)
// ...etc.

// part of astro syntax. have to comment this here
// ---

//render HTML
<BaseLayout pageTitle={title}>
    <Fragment set:html={postHTML} />
</BaseLayout>

I don’t have any burning questions anymore, but I’m still pretty clueless about when to use a dynamic preview URL.

You say that a good use case is having templatized content with content based on each slug. Seems like this is kind of what I’m doing here (see code above). I still don’t understand what a dynamic URL would get me.

You say I wouldn’t have to create a Builder entry for each page (so in this case - for each blog post?). That seems interesting… But I don’t get it :slight_smile:.

I might be missing something fundamental. I read the phrase ‘the preview url should point to where your content in your app will eventually live.’ and I’m like: hmmmm… do I fundamentally misunderstand something? :laughing: Do You mean that the page that the preview URL points to should in most cases look like the content that’s being edited (to simulate how the content would look on the site)? That’s the only meaning that makes sense to me right now. And that’s how I’m doing it in my project:

// /builder_preview
// compare to code in [...slug].astro above 

<BaseLayout>
    <builder-component model={builderModel} api-key={builderAPIpublicKey}
    ></builder-component>
    <script async src="https://cdn.builder.io/js/webcomponents"></script>
</BaseLayout>  

Seems to me like I’m a little out of my depth here. The preview URL alone messes with my brain, let alone a dynamic one.

Feel free to pass this on to the docs team. I would love a guide or code examples that spell out these use cases and the PROs and CONs of a static vs. dynamic preview URL.

Any further explanations are still appreciated, of course :upside_down_face:

1 Like

Hi @habbeda apologies for the delayed response here!

Essentially, when you enter a Preview URL in builder, our Visual Editor loads an iFrame of that url, and then will locate the html <builder-component /> and use client side logic to override the content within that element with whatever you are editing inside the Builder Visual Editor. The URL that you enter in the preview URL field will need to be available to you (either on your local machine, or on a deployed app) and have the builder content to be able to work and display the content correctly.

Having a dynamic preview URL means that Builder with generate a previewURL based on the logic you define in your model’s schema, so for example if you have the preview url set to be something like https://www.you-website.com/${content.data.slug}

So this just means that assuming you have pages available at that URL that have Builder content, it will display the WSIWYG editor on that page in the Builder Visual Editor. If you have your code set up such that Builder is fetching content in your app based on the slug, then that means if you set up a single template, you can theoretically generate all of the blog pages for a given slug without having to create a content entry for each entry within Builder.

Hopefully that makes it a little more clear? Let me know if you have any further questions!

1 Like