How to set the Page URL with the Write API

I’m trying to create a content page with the Write API. I’ve gotten very close. The thing I cannot figure out is how to set the Page URL. I can set the title, name and description, but the Page URL is not documented anywhere. There is no example to set it.

const addLandingPageContent = async (data: LandingPageModel) => {
  const baseUrl = "https://builder.io/api/v1";
  const url = `${baseUrl}/write/page`;
  const key = process.env.NEXT_PUBLIC_BUILDER_IO_PRIVATE_API_KEY;
  const postData = {
    name: data.name,
    data: {
      pageUrl: '/' + data.name,
      title: data.title,
      description: data.description,
    }
  };
  return axiosInstance.post(url, postData, {
    headers: {
      Authorization: `Bearer ${key}`
    }
  });
};

So this code indeed creates the page with the title and description. The page URL is empty. I tried various spelling and nothing works. Where is the detailed documentation? Normally if documentation is crap you can simply look through the source code for answers but that is not possible here…I can’t find the source code. My “3 minute” integration is going on 4 weeks now and I am really tired.

Hello @AQuirky

Thank you for reaching out — I understand how frustrating it can be when documentation isn’t clear, and I appreciate your persistence in getting this working.

To set the Page URL when creating content via the Write API, you’ll need to include a query property in your request body. This is what defines the page’s routing and associates a URL path with the content entry.

Here’s an example of a full payload that works for us:

{
  "ownerId": "db60bf3db7fa4db7be81ef05b72bd720",
  "lastUpdateBy": null,
  "@version": 4,
  "name": "Write API test - URL parameter",
  "published": "published",
  "query": [
    {
      "@type": "@builder.io/core:Query",
      "property": "urlPath",
      "operator": "is",
      "value": "/write-api-test-url-parameter"
    }
  ],
  "data": {
    "themeId": false,
    "title": "Write API test - URL parameter"
  },
  "metrics": {
    "clicks": 0,
    "impressions": 0
  },
  "folders": []
}

In this structure:

  • The query array is where you define the urlPath using a type of @builder.io/core:Query.

  • This is the required way to bind a URL to a page model in Builder.

You can update your existing postData in the code like so:

const postData = {
  name: data.name,
  published: "published",
  query: [
    {
      "@type": "@builder.io/core:Query",
      property: "urlPath",
      operator: "is",
      value: '/' + data.name,
    }
  ],
  data: {
    title: data.title,
    description: data.description,
  }
};

Let us know if that works for you — and again, thank you for your patience. I’ll also pass this feedback along so we can improve the documentation around the Write API.

Thanks,

Yes, this worked. But I don’t know why. Why is a query used to set a value? It doesn’t make sense. Where is all the detailed documentation? What other operators are there besides “is”. What query language is this anyway? It seems like a Domain Specific Language. If so, where is the DSL documentation? Why can’t I browse the source to figure this out for myself? You have to give me one or the other: either detailed documentation or un-obfuscated source code and you have done neither. You are wasting my time.

Hello @AQuirky,

I completely understand the confusion — it’s not obvious at first why something like the “Page URL” would be controlled via a query block instead of a direct property.

The short version is: in Builder.io, content models aren’t hard-wired to a single page or URL. A “Page” is really just an entry in a model, and what makes it appear at a specific route is a targeting rule — what Builder calls a query.

That query can match things like:

  • urlPath — the URL path to render the content on

  • locale — for language-specific content

  • device — for device targeting

  • Any custom targeting attributes you’ve defined

For example:

{
  "@type": "@builder.io/core:Query",
  "property": "urlPath",
  "operator": "is",
  "value": "/my-page"
}

…means “render this entry when the URL path is exactly /my-page.” Without this, Builder has no way of knowing what route should map to that entry — which is why the “Page URL” appears blank in the UI if you don’t set it.

Why it’s different from title or description
Those are input fields directly stored as part of the content data. Targeting attributes like urlPath or device are not intrinsic content fields — they’re rules that control when and where that content is served.

About the “query language”
It’s not a full DSL like SQL or GraphQL — it’s a custom JSON format (@builder.io/core:Query) used internally by Builder for targeting. Common operators include:

  • is/isNot – exact match/ no match (most common)

  • contains – substring match

  • startsWith / endsWith.

You can find a full list of supported operators and more details in the official docs here:

And here’s an example of the Write API content JSON:

https://www.builder.io/c/docs/write-api#example-content-json

I hope this clarifies how Builder handles routing and targeting. Please let me know if you have any further questions!

1 Like

Yes, thanks very much for your detailed response. Indeed I admit the documentation you referenced is detailed and complete. I guess the reason I couldn’t find it that I didn’t search for “targeting” as I didn’t realize that was what I was doing when setting the page URL. Perhaps if the “Page URL” field in the editor was in a section labeled “targeting” I would have had a clue as to what to search for. Also at the top of the documentation page it says Enterprise Plans which the $40K club. Too rich for either me or my clients. So I have been ignoring any documentation that is introduced by that label.

1 Like