Optimizely SaaS

  • Page Owner: Not Set
  • Last Reviewed: 2025-07-22

Optimizely SaaS

Environments

Note: These may change slightly as we learn how best to work in this environment. Currently, the environments are treated as:

  • Test1 - Local environment
    • Test1 is tied to the localhost domain and is used for all local development.
    • Everyone must share the same instance and may need to work in different branches of the content tree as necessary.
    • No server is set up for this environment (just localhost), no branch is tied to this environment.
  • Test2 - QA review / UAT environment
    • Once the project is deployed to production, Test2 is the environment code is deployed to for review prior to production.
    • QA server points to this environment.
  • qa branch deploys to QA server
  • Prod - Production
    • Production server points to this environment.
    • main deploys to the Production server.

Hooks

To support Increment Static Regeneration (ISR) on Vercel, or similar cache clearing on other hosting, we use the content hooks API to make a request to the server to clear the ISR cache when a page changes.

  • We use the Content Hooks API to create a hook. Example of API, and the call to the API.
  • When content changes, the hook calls the URL we passed to it.
  • Because we can't control the hook payload, we call an API endpoint that we control in the site itself.
  • The API endpoint we control then calls the site itself with the clear code. Example here.

Managing Content Types

Content Types are not managed in code as in PaaS. So we use the following process to make changes and sync them across environments:

  • Make the change in the Test 1 environment manually through the UI.
  • Sync all content types to your local branch using blend-auto. Example implementation.
  • Diff the content types JSON to pull out the new or updated properties. Put those changes in a patch file.
    • A patch file will contain just the properties or values that have changed. Example patch file.
  • Push your patch file to the next environments using blend-auto. Example implementation.
    • The command in the above example would be something like .\patch-prod.ps1 -PatchFile .\patches\0001-fix-search-page.json -ContentType SearchPage

Note: This assumes that content changes will not break other environments. For breaking changes, this will need to be coordinated with deployments. In general, we try to avoid breaking changes as much as possible.

Note: This may change as our process evolves.

Content Contracts

Optimizely SaaS does not have inheritance. But it does have Content Contracts, which act like an interface. It's a contract (a list of properties) that a piece of content must implement.

An example content contract from the Blend site.

To implement a content contract for a content type, patch the content type, setting the contract value:

{
  "contracts": [
    "BasePageContract"
  ]
}

Content Modeling

  • Bundle configured properties into blocks and reference that block (rather than duplicating the property configuration in a bunch of places)
  • Be intentional about allowing types in content areas. Recursive queries do not work well.

GraphQL

  • Break queries into fragments, fragments per block type / page type. This tends to be more maintainable than a single, massive query.
    • Also, the fragments produce types that can be used in TypeScript in multiple places. For example, the BodyButtonBlock GraphQL fragment will produce a BodyButtonBlockFragment type that can be used anywhere you want to accept an instance of that block type.
  • For Contentarea Queries, include all/only fragments you would expect in the content area. See example content area query.

SvelteKit Routing Groups

We load both the page and surround data from the +layout.server.ts file, to make the data available to both the surround and the individual page views. For previews, we must load slightly different data, so we need to separate the "public" live view, and the "private" preview view. To support this, we use several groups to separate the site into logical "areas". The groups do not effect routing, but do allow us to use different layouts (or no layout) as necessary. These route groups are:

  • (opti) - Used for CMS preview and on-page-editing (not yet working)
  • (private) - The API path for the hook for ISR invalidation.
  • (public) - All public-facing live content
  • (static) - A fake static version of the site, similar to the old static gulp-generated sites.

Other Important Notes

  • When querying for a page via Content Graph, one must check both hierarchical URL and default URL.
  • At time of writing, a bug in the sync API does not sync RTE choice.
  • At time of writing, there is no Textarea UI hint. All string fields are either HTML editor or a single line.
  • Use a Content Area Item instead of Content Reference for images, otherwise you can’t pull in content from the referenced item (such as alt text).