# Prepr Documentation - Full Export > Complete Prepr CMS documentation in one file. --- # Start building with Prepr This is the place to learn all about Prepr. Explore the topics below to start learning or create your [free account here](https://signup.prepr.io) if you haven't done so already. If you need any help, don't hesitate to reach out: [Join our Slack](https://slack.prepr.io) or [Reach out to our support team](https://prepr.io/support). ## Connect a front-end framework ## More resources Source: https://docs.prepr.io/index --- # Quick start guide *Estimated duration: 15-30 minutes* ## Introduction Prepr allows you to develop a dynamic, data-driven, web application with ease. This tutorial explains how to get started with Prepr. We will cover all the basics: modeling content types, adding content and images and retrieving content using the API. Follow the step-by-step guide below. ## Use case This tutorial explains how to manage articles and author profiles in Prepr and retrieve that content using the GraphQL API. For example, to create a blog. You can apply these principles to all kinds of situations.  ## Step 1: Create an environment If you haven't already done so, go to https://signup.prepr.io/ and sign up for a Prepr account. 1. After you sign up, you will be prompted to add an environment. Enter a **Name** and choose the **Default locale** and **Development stage**.  2. On the next screen, you will be prompted to either load demo data or to start from scratch. While importing demo data can help you explore Prepr features with preset schema and content items, for the purpose of this tutorial we recommend starting from scratch to experience the whole setup process yourself. To get a clean environment, click **Start from scratch**.  That’s it. You’ve created your first environment in Prepr. In the next step, you can add models and fields for our blog use case. ## Step 2: Create content models A headless CMS allows you to define a structure for your content according to your needs. We call that content modeling. For this example, you need an **Article** model and a **Person** model.  Let’s create these models in Prepr: 1. Click the **Schema** tab to open the *Schema Editor*. 2. In the *Models* section, click the **+ Add model** link. 3. Choose **Multi-item model** and enter *Person* in the **Display name** field and click **Next** and **Save**. Check out the [Models doc](/content-modeling/managing-models#manage-settings) for more details on additional options.  5. Drag and drop the **Text** field type, from the list on the right into your model. a. Enter *Name* in the **Display name** field and click **Save**. 6. Drag and drop another **Text** field type, from the list on the right into your model. a. Enter *Bio* in the **Display name** field. b. Click the **Settings** tab. c. Select *Text area* and click **Save**. 7. Drag and drop the **Assets** field type, from the list on the right into your model. a. Choose the **Multi-asset field** option. b. Enter *Image* in the **Display name** and click **Save**. Your Person model should now look like this:  Now you can add the Article model. 1. Click the **+ Add model** button on the left. 2. Choose the **Multi-item model** option, enter *Article* in the **Display name** field, click **Next** and **Save**. Check out the [Models doc](/content-modeling/managing-models#manage-settings) for more details on additional options. Your model should look something like this:  And add the fields: 4. Drag and drop the **Text** field type, from the list on the right into your model. a. Enter *Headline* in the **Display name** field and click **Save**. 5. Drag and drop another **Slug** field type, from the list on the right into your model. a. Click **headline** in the box below to fill the Slug template with `{headline}`. b. Click **Save**. Now we’re going to add the author field. This is not a text field, but a reference to the Person model you created earlier. A reference field allows you to link to other content items, as in this case to a Person. 6. Drag and drop the **Content reference** field type, from the list on the right into your model. a. Enter *Author* in the **Display name** field. b. Select the *Person* model and click **Save**.  7. Next, add the rest of the fields below in the same way as described above: - *Intro* - **Text** field - *Image* - **Assets** field - *Content* - **Dynamic content** field - *Tags* - **Tags** field See an overview of [all field types](/content-modeling/field-types). Your model should look like the image below.  ## Step 3: Create content items Now that you've created the models, you can add content items. Start by adding a *Person*: 1. Go to the **Content** tab, click the **Add item** button and choose **Person**. 2. Fill out the **Name** and **Bio** fields. 3. Drag and drop an image into the **Image** field or click it to add an image from your local storage.  6. Click the **Publish** dropdown and select the **Publish and close** option. Now, add an article: 1. Click the **Add item** button again. 2. This time, select **Article**. 3. Enter a **Headline**. You will notice the slug field automatically being populated. Copy this slug value to retrieve your article in [Step 5](#step-5-retrieve-a-single-article-from-the-api). 4. Click the **+ Person** link to choose and add a person to the *Author* field.  Now fill in the remaining fields. 6. Add some text and images to the *Content* field. 7. Add some tags in the *Tags* field. Add tags by selecting an existing tag in the list, or adding a new tag and clicking **Enter**. 8. Click the **Publish** dropdown and select the **Publish and close** option. The next step is to retrieve the content items from the API so you can display the content in your web application. ## Step 4: Retrieve articles from the API The easiest way to experience content retrieval through the API is to use the API explorer: 1. Click the icon and choose the **Access tokens** option. 2. Click to open the *GraphQL Production* token details. 3. Open the API explorer by clicking the **Open API Explorer** link.  Make sure you see a green dot and your access token at the end of the url. If you cannot connect, please contact support.  With the explorer, you can easily create and test API queries. Let’s create a query to retrieve a list of all articles: 4. Add the following query ```graphql copy query { Articles { items { _id headline } } } ``` Note that you can retrieve the ID for all content items using the system field *\_id*. You can recognize system fields by the underscore in front of the field name. Check out [all system fields](/graphql-api/schema-system-fields) for more information. 5. Click **Run** to execute the query The result should look something like this: ```json copy { "data": { "Articles": { "items": [ { "_id": "4fcad70d-2beb-4886-bd8d-1753020bf315", "headline": "How to get the best deals : Insider tips and tricks" } ] } } } ``` As you can see, the response includes a list of all the items. At the moment, there is only one article, which is listed including its ID and headline. Let's expand the query so that you retrieve the other fields as well. ```graphql copy query { Articles( where: { _publish_on_gt : "2025-06-15T09:00:00+00:00" } ) { items { _id _slug _publish_on author { _id name image { url(width:800) } } headline image { url(width: 1000) } intro tags { body } } } } } ``` In the query above, we added a condition to get all articles published on or after June 15th, 2025. This query includes the following fields that we want to see in the result: - *\_slug* field - *\_publish\_on* field to retrieve the publication date - *author* field to retrieve reference fields ([learn more](/graphql-api/schema-field-types#content-reference)) - *image* field to retrieve assets ([learn more](/graphql-api/schema-field-types#assets)) - *content* field to retrieve a dynamic content field ([learn more](/graphql-api/schema-field-types-dynamic-content-field)) - *tags* field to retrieve tags ([learn more](/graphql-api/schema-field-types#tag)) Check out the documentation for [all field types](/graphql-api/schema-field-types) and how to retrieve [multiple content items](/graphql-api/fetching-collections) for more information. - Run the query. The response should look something like this: ```json copy { "data": { "Articles": { "items": [ { "_id": "38a05b5c-98cf-4275-8d2b-3748f49cc104", "_slug": "how-to-get-the-best-deals-insider-tips-and-tricks", "_publish_on": "2025-10-07T12:08:00+00:00", "author": [ { "_id": "dee58849-bb0a-4ceb-a288-7adc9e623602", "name": "Emma Carter", "image": { "url": "https://ml98.stream.prepr.io/6iku17cg8lc8/w_800/emma-carter-profile.jpg" } } ], "headline": "How to get the best deals : Insider tips and tricks", "image": { "url": "https://ml98.stream.prepr.io/6i57ud05jnjq/w_1000/business-deal-photo.jpg" }, "intro": "Want to lease a car without overpaying? Follow these expert tips to negotiate the best lease deal, avoid common pitfalls, and maximize your savings.", "tags": [ { "body": "car deals" }, { "body": "tips and tricks" } ] } ] } } } ``` And voila, a JSON response containing all the data from your content items. We just queried a list of articles that you can use to show on a blog overview page. On that page, you give each item a unique URL based on the slug—for example: ``` https://yourdomain.com/articles/how-to-get-the-best-deals-insider-tips-and-tricks ``` ## Step 5: Retrieve a single article from the API You want to show the whole article when a visitor clicks the link. Retrieving a single content item can be done using the below query. Replace the slug value with the value that you copied in [Step 3](#step-3-create-content-items). ```graphql copy query { Article( slug: "how-to-get-the-best-deals-insider-tips-and-tricks") { _id headline } } ``` In the query above, we specify a condition to return an item with the matching slug. Update the slug value in quotes to match the slug of the article that you created. When you run this query you get the following result: ```json copy { "data": { "Article": { "_id": "38a05b5c-98cf-4275-8d2b-3748f49cc104", "headline": "How to get the best deals : Insider tips and tricks" } } } ``` The last thing you need to know is how to retrieve the article content. Expand the query like this: ```graphql copy query { Article(slug: "how-to-get-the-best-deals-insider-tips-and-tricks") { _id headline author { _id name image { url(width:800) } } intro image { url(width: 1000) } content { ... on Text { format body } ... on Assets { items { url(width:600) } } } tags { body } } } ``` You've already seen most of the fields when you retrieved the article list. The content field is new. The preceding query shows how to retrieve a dynamic content field. Per element type, you fetch the information. In this case, for text elements and assets only, however, there are many more element types. Check out the [dynamic content field documentation](/graphql-api/schema-field-types-dynamic-content-field) for all the details. Here’s the result: ```json copy { "data": { "Article": { "_id": "38a05b5c-98cf-4275-8d2b-3748f49cc104", "headline": "How to get the best deals : Insider tips and tricks", "author": [ { "_id": "dee58849-bb0a-4ceb-a288-7adc9e623602", "name": "Emma Carter", "image": { "url": "https://ml98.stream.prepr.io/6iku17cg8lc8/w_800/emma-carter-profile.jpg" } } ], "intro": "Want to lease a car without overpaying? Follow these expert tips to negotiate the best lease deal, avoid common pitfalls, and maximize your savings.", "image": { "url": "https://ml98.stream.prepr.io/6i57ud05jnjq/w_1000/business-deal-photo.jpg" }, "content": [ { "format": null, "body": "
Leasing a car can be a great way to drive a new vehicle without the high upfront cost of purchasing. However, not all lease deals are created equal. If you want to save money and get the most value, follow these expert tips to secure the best lease deal possible.
" }, { "format": null, "body": "1. Understand the Key Lease Terms
" }, { "format": null, "body": "Before negotiating, it’s essential to understand how leases work. Here are the critical terms you should know:
" }, { "format": null, "body": "• Capitalized Cost (Cap Cost) – The vehicle’s price before lease calculations. Like when buying, this can be negotiated down.
" }, { "format": null, "body": "• Residual Value – The car’s estimated value at the end of the lease. Higher residual values mean lower monthly payments.
" }, { "format": null, "body": "• Money Factor – Equivalent to the interest rate on your lease. The lower, the better.
" }, { "format": null, "body": "• Mileage Limit – Most leases have annual limits (e.g., 10,000–15,000 miles). Exceeding this incurs extra charges.
" }, { "format": null, "body": "2. Negotiate the Capitalized Cost
" }, { "format": null, "body": "Many people assume lease prices are fixed—they’re not! You can negotiate the cap cost just like when buying a car. Research the market price of the vehicle and ask for a discount. The lower the price, the lower your monthly lease payments.
" }, { "format": null, "body": "3. Look for Manufacturer Lease Specials
" }, { "format": null, "body": "Car manufacturers frequently offer special lease deals, reducing monthly payments, down payments, or interest rates. These can include:
" }, { "format": null, "body": "• Cash rebates
" }, { "format": null, "body": "• Loyalty discounts
" }, { "format": null, "body": "• Zero down-payment leases
" }, { "format": null, "body": "Check official websites and dealership promotions for these offers.
" }, { "format": null, "body": "4. Choose a Car with a High Residual Value
" }, { "format": null, "body": "Cars that retain their value well will have a higher residual value, leading to lower monthly payments. Brands like Toyota, Honda, and Lexus typically have strong resale values.
" }, { "format": null, "body": "5. Understand Lease Fees and Extra Costs
" }, { "format": null, "body": "Be aware of the following potential extra costs:
" }, { "format": null, "body": "• Acquisition Fee – A fee for setting up the lease.
" }, { "format": null, "body": "• Disposition Fee – Charged at the end of the lease if you return the car.
" }, { "format": null, "body": "• Excess Mileage Charges – Avoid these by choosing a lease with the right mileage limit.
" }, { "format": null, "body": "6. Consider a One-Pay Lease
" }, { "format": null, "body": "Instead of making monthly payments, some dealerships offer a single lump-sum payment lease. If you can afford it, this may save you thousands in interest fees.
" }, { "format": null, "body": "7. Final Tip: Read the Lease Agreement Carefully
" }, { "format": null, "body": "Before signing, review every detail of the lease to avoid hidden costs. If anything is unclear, ask for clarification.
" } ], "tags": [ { "body": "car deals" }, { "body": "tips and tricks" } ] } } } ``` For more details check out the [fetching single content items](/graphql-api/fetching-single-items) API reference. Congratulations, you have completed your first steps with Prepr. From modeling and creating content items to retrieving content using the API. With that, you have mastered the basics of Prepr. ## Step 6: Connect your front end The next step is to connect your web application. We have guides for all major front-end frameworks to quickly get you up and running. - [Next.js](/connecting-a-front-end-framework/nextjs) - [Nuxt](/connecting-a-front-end-framework/nuxtjs) - [Laravel](/connecting-a-front-end-framework/laravel) - [Angular](/connecting-a-front-end-framework/angular) - [Node.js](/connecting-a-front-end-framework/nodejs) - [PHP](/connecting-a-front-end-framework/php) - [React](/connecting-a-front-end-framework/react) - [Vue.js](/connecting-a-front-end-framework/vuejs) ## Want to learn more? Of course, there is much more to explore. For example, with Prepr, you can perform A/B testing, present recommendations and personalize the visitor journey. For more advanced topics, please refer to the rest of the documentation, or contact one of our specialists. Check out the following chapters: - [A/B testing](/ab-testing) - [Personalization](/personalization) - [Recommendations](/recommendations) ## Schedule a free consultation Do you want to get started but still have questions or want a demo? [Schedule a free call](https://prepr.io/get-a-demo) with a Prepr solution engineer. During the consultation we can provide recommendations on topics like: - Content modeling for the desired use case - Working with multiple environments, websites and languages - Creating personalized experiences for your website visitors - A/B testing and other optimization strategies Source: https://docs.prepr.io/quick-start-guide --- # Changelog Beautiful new features and important updates are added to Prepr on a daily basis. This changelog gives you an insight into the most eye-catching releases. Be aware that updates can be rolled out in phases so they may not always be available in all Prepr environments at the same time. **Latest** | [2025](/stay-updated/changelog2025) | [2024](/stay-updated/changelog2024) | [RSS Feed](/changelog/rss.xml) ## Environment-scoped preview for shared model *May 13th, 2026* Previously, when you set up preview URLs in a shared model, editors in any environment in the organization could see the full list of preview URLs you added. Now, you can scope preview URLs to individual environments when setting them up.  This cleans up the UI for visual editing as editors only see preview options relevant to their environment, saving them time and avoiding unnecessary scrolling and clicking wrong preview options. For more details, check out the [preview setup guide](/project-setup/setting-up-previews#scoping-environments-for-a-preview-url). ## AI-generated text for images *May 7th, 2026* Based on your feedback on the [Beta release](#ai-generated-alt-text-for-images-beta-release), we’ve officially launched AI-generated text for images. When uploading new images get AI-generated alt text, descriptions, or comma-separated keywords instantly.  This means you save time on manual entry and boost SEO rankings without the extra effort. Check out the [AI integration guide](/integrations/image-processing/ai) to activate this feature. ## Uploading files without an official MIME type *April 24th, 2026* Previously, when you uploaded a file without an official MIME type, this file could not be processed. For example, files with a `.bgi` extension. We've updated the file upload to allow files without an official MIME type, using the file extension to set a fallback [MIME type](https://mimetype.io/all-types). Also, when a MIME type has multiple extensions, we keep the original extension of the file. This means your files remain in their original format, ready to use in content items and processed. For more details, check out the [uploading assets](/content-management/managing-assets/managing-assets#uploading-assets) doc for more details. ## Introducing the Propeller commerce integration *April 17th, 2026* The new *Propeller* integration allows your team to easily include Propeller products in content items.  This means content editors can work more efficiently and error-free by simply choosing the relevant Propeller entries directly in Prepr. For more details, check out the [Propeller integration guide](/integrations/propeller). ## Defining percentage-based field widths *April 16th, 2026* With a new option to set field width, we've replaced the field columns fixed structure with a more flexible percentage-based option for model and component fields.  This visual improvement means editors can more easily and quickly scan and edit text fields in content items. Check out the [models guide](/content-modeling/managing-models#defining-field-width) for more details. ## Improved schema sync visibility *April 16th, 2026* We've updated the schema UI and since syncing is an important schema action, we've moved the sync schema action to the top of the page.  With this update, you also have clarity on which repo, branch and commit the schema was last synced with and whether the schema is in sync with the branch or vice versa. Check out the [schema sync guide](/development/working-with-cicd/syncing-a-schema#check-the-result) for more details. ## New field setting to declutter content item filter menus *April 16th, 2026* With the new **Show in filters** setting, developers can declutter the editing experience by hiding *List*, *Stack* and *Content reference* fields from the content item filter menus.  It’s about reducing noise and helping your editors focus on the data that actually matters. For example, when editors search *Product* content items, the product rating (list field) doesn't add value to the search because it would return too many results. Check out the field settings of the [stack field](/content-modeling/field-types#stack-field), [list field](/content-modeling/field-types#list-field) or [content reference field](/content-modeling/field-types#content-reference-field) for more details. ## Searching through your schema instantly *April 16th, 2026* Find your models, components, enumerations, and remote sources instantly with the new schema search bar.  This way you stay focused on building your schema rather than searching. Check out the [models guide](/content-modeling/managing-models#search-models) for more details. ## Improved commenting on content items *March 31st, 2026* You can now add content item comments to specific fields and for a specific locale of the content item, making it possible to provide more granular and actionable feedback.  This means you can follow your editing review process directly in Prepr speeding up your team collaboration and publication of content items. Check out the [collaboration guide](/content-management/collaboration#commenting) for more details. ## Manage content with AI agents using the new Prepr MCP server *March 27th, 2026* With the Prepr MCP server, you can create AI agents to manage content in your Prepr CMS environment with natural language prompts. For example, editors who usually write article posts in a tool like Notion can ask the AI agent to create content items for these posts.  This means you can automate the grunt work so your team can focus on more strategic tasks. Check out the the [Prepr MCP guide](/prepr-mcp) on how to set it up for AI agents. ## Managing custom event types *March 17th, 2026* You can now set the **Display name** and the **Visibility** of custom event types directly in Prepr. For example, to change a technical event type name `Scrolled50` to something like *Scrolled 50% of the page* or to hide old events with an outdated event type.  This means that you and your marketers get a clear clutter-free view of events and only see relevant metrics. Check out the [Event type settings](/data-collection/recording-events#managing-custom-event-types) for more details. ## Expanded trigger criteria for *content\_item.invalidated* webhook event *March 12th, 2026* We’ve updated the criteria for the `content_item.invalidated` webhook event to provide better synchronization between your external systems and published content. Previously, this event was triggered for external system changes to a remote source item. Now, it also triggers for [API `PATCH`](/mutation-api/content-items-create-update-and-destroy#patch-a-content-item) updates. This means if you update a published content item via the API `PATCH` request, the `content_item.invalidated` event will fire automatically. Check out the [webhooks guide](/development/best-practices/webhooks#content-item-events) for more details. ## Fixed validation for required fields after hidden conditional sections *March 12th, 2026* We fixed an issue where required fields following a conditional section were incorrectly ignored when that section was not shown. Previously, this could allow content to be published without completing required fields. With this fix, required fields after a hidden conditional section are now validated correctly before publication. ## Schema validation based on new Prepr schema spec *March 11th, 2026* We've just released a [Prepr schema validation](https://github.com/preprio/action-schema-validation) using the new [Prepr schema spec](https://github.com/preprio/action-schema-validation/blob/main/spec/2026-03-05.json5). Now, you can automatically validate your schema JSON files in *GitHub* to ensure you import a valid Prepr schema every time. This release lays the foundation for the next steps to use AI to generate a fully validated Prepr schema. For more details, check out the [schema validation guide](/development/working-with-cicd/validating-a-schema). ## Prepr Next.js package version 2.2.5 is available *March 10th, 2026* We've just released a new version of the Prepr Next.js package. Version 2.2.5 includes a manual override of the `fast-xml-parser` to solve the `CVE-2026-25128` DoS vulnerability. We strongly recommend you upgrade your installation of the Prepr Next.js package, where applicable. For more details, check out the [Prepr Next.js package guide](/prepr-nextjs-package). ## Remote source settings preserved in schema sync *March 5th, 2026* We’ve updated the behavior of the *Direct schema sync* and the schema import (via *GitHub*, *GitLab*, *Bitbucket* or *Azure DevOps*) for existing remote sources. Previously, an existing remote source was always fully synced. From now on, the URL, headers, and image domains of an existing remote source will no longer be updated during a schema sync and will be ignored instead. This matches the current behavior of *Preview URLs* and helps prevent manual rework after each sync, especially when test or development URLs need to remain unchanged. Check out the [Schema sync guide](/development/working-with-cicd/syncing-a-schema) for more details. ## New Prepr Next.js package version 2.2.x is available *March 3rd, 2026* The newest version of the Prepr Next.js package now automatically detects and handles stega encoding. Stega encoding uses hidden characters so editors can click and edit content directly from the preview. This update means you no longer need to write extra code to clean up these hidden characters which could cause misalignment of some UI elements in the live preview. Check out the [Prepr Next.js package guide](/prepr-nextjs-package) for more details. ## Legacy API deprecation on August 1st, 2026 *February 27th, 2026* As part of our effort to streamline our API infrastructure, the legacy Prepr API endpoint `api.eu1.prepr.io` will expire and be removed on August 1st, 2026. If your application currently uses `api.eu1.prepr.io`, update your implementation before then. For write operations (mutations), update your endpoint to `mutation.prepr.io`. For read-only operations (queries), we strongly recommend updating your endpoint to `cdn.prepr.io`. Contact [Prepr support](mailto:support@prepr.io?subject=Request%20AI%20activation%20for%20image%20text%20values) if you have any specific questions. ## AI-generated alt text for images (Beta release) *February 25th, 2026* When uploading new images you can now get AI-generated text values instantly. For example: alt text, specific descriptions, or comma-separated keywords. This means you save time on manual entry and boost SEO rankings without the extra effort.  Contact [Prepr support](mailto:support@prepr.io?subject=Request%20AI%20activation%20for%20image%20text%20values) to activate AI-generated text for images in your environment. ## Improved linked content visibility *February 20th, 2026* With the improved linked content visibility, you can now get a high-level view of linked content items from the content item list.  This removes the need to open individual items to investigate dependencies and therefore speeds up your review of linked content items. For more details, check out the [content management doc](/content-management/managing-content/managing-content-items#view-linked-content-items). ## SSO-ready invites speed up sign-ins *February 12th, 2026* Inviting new users to Prepr is now smoother when you use SSO, for example, *Microsoft Entra ID* or *SAML 2.0*. As an administrator, you can now assign roles upfront by simply inviting the new SSO user. This means users no longer need to wait for an admin to grant access after their first SSO sign-in. When the user clicks the **Activate** link in the invite email, Prepr automatically routes them to the correct SSO sign-in flow (instead of email + password), so they can start working right away. Check out the [managing users guide](/project-setup/managing-users#send-invitation-to-sign-in) for more details. ## New webhook event for remote source item changes *February 10th, 2026* We’ve added a new event to our webhooks: `content_item.invalidated`. This new event triggers whenever remote source data linked to a content item changes. This means you can now set up a webhook to notify your front end the moment the remote source data becomes stale. For more details, check out the [webhooks guide](/development/best-practices/webhooks#content-item-events). ## Additional granular permissions to manage content items *February 10th, 2026* In addition to the [action-based content permissions](/stay-updated/changelog2025#introducing-granular-permissions-to-manage-content-items) we released recently, you can now extend user role permissions and content item access with the following additional features: - *Direct content item sharing* - You can now grant specific users access to individual content items. This allows you to easily work with freelancers or agencies while maintaining strict data privacy.  - *On-demand access requests* - When users try to open a linked content item they don't have access to, they can directly request access within Prepr with this new workflow.  - *Show my items only* - You have a new setting to allow a user to only access content items they've created or items explicitly shared with them. For example, a freelance editor who only needs to access content items they're assigned to work on.  - *Scoped content access* - Allows users to access only content items in specific workflow stages. For example: A translator who only needs to access content items in the *Review* or *Translation* workflow stages.  These new access right features enhance data security, prevent accidental errors and increase user focus for certain roles, like freelance editors. Check out the [user role guide](/project-setup/managing-roles-and-permissions#content-management-permissions) for more details. ## Introducing the ProspectPro integration *January 12th, 2026* With the new ProspectPro integration, you can easily connect Prepr to this B2B prospecting platform. This integration lets you segment website visitors based on their company industry and company size.  By segmenting visitors this way you can personalize content for an enhanced user experience for your B2B audience. Check out the [ProspectPro integration guide](/integrations/prospectpro) for more details. ## Activate integration with Prepr directly in HubSpot Marketplace *January 6th, 2026* We've introduced a streamlined authorization flow that allows you to activate the integration with Prepr directly from the HubSpot Marketplace. This makes the process seamless and fully contained within the HubSpot environment.  Check out the [HubSpot integration guide](/integrations/hubspot) for more details. Source: https://docs.prepr.io/changelog --- # Prepr's product roadmap We’re constantly improving our products, integrations, and services. Learn about features we're working on and upcoming improvements. ## Q1 & Q2 2026 ### Enhanced *Ask AI* with custom and inline prompts We are introducing an *AI Optimize* option in *Dynamic Content* Fields, allowing users to refine or improve content automatically. By expanding the existing *Ask AI* functionality with custom prompts and inline prompting, we're enabling more flexible and context-aware AI assistance directly within the editor. ### AI-powered schema suggestions and templates To streamline the schema design process, Prepr will introduce AI-generated suggestions and ready-to-use schema templates. This feature will help users create efficient, consistent content models more quickly by recommending fields, structures, and best practices based on content type and use case. ### Improve experiment list and experiment setup guidance We’ll improve the experiment overview and setup flow to make experiments easier to create, understand, and learn from. This includes clearer guidance during setup, better visibility into required tracking and metrics, and a more informative experiment list so teams can quickly see status, configuration quality, and next steps. ### Remote source specs files By providing clear spec files with improved guidance, we'll make it easier for you to build your own remote source for external data imports. With this update, we are simplifying setup, reducing integration guesswork, and helping you to validate remote source behavior more quickly and consistently. ### Environment management Improve working with multi-site set up (shared schema). Export and import environment settings (via Git). Set environments per preview URL (to determine which URL is visible in which environment). Also select environments in reference/stack field, to select the environments from which content can be chosen. ### Multiselect enumeration Currently it is only possible to choose 1 value from a list (enumeration). As per your request, we'll add the option to use a multi-select list. ### Improved content checks for GEO/AEO Use AI to help create stronger content in Prepr, with built-in guidance on how to make content index-ready. This roadmap item focuses on assisting editors with content quality, structure, and completeness, so content is easier to optimize for search, discovery, and downstream AI or indexing use cases. ### Automatic redirects on slug changes To prevent broken links and ensure a smooth user experience, we’re introducing automatic redirects when a slug is manually changed in a content item. This means editors no longer need to manually create redirects—visitors will always be guided to the correct page. ### Improvements on content item comments section The upcoming improvements to the commenting option, designed to provide more precise and collaborative feedback capabilities. This update will introduce field-level commenting, allowing users to leave comments on specific fields rather than entire content items. Additionally, comments will support locale segregation, user assignment, threaded replies, and resolution tracking. These enhancements aim to streamline feedback workflows, foster better collaboration across teams. ### Improve CRM/CDP-integrations for segmenting We are enhancing CRM/CDP integrations to streamline the use of external audience segments for adaptive content delivery. This update will enable seamless integration with external CRM/CDP platforms, allowing you to leverage existing segments - such as those created for specific campaigns or based on leads - directly within your website. By utilizing these segments, you can deliver highly targeted, adaptive content to enhance engagement and personalization strategies, ensuring a more impactful and relevant user experience. Source: https://docs.prepr.io/roadmap --- # Setting up your production-ready project *Welcome to Prepr, a data-driven headless CMS with a built-in personalization engine and optimization features. Learn about the different parts that you need to set up your project with Prepr and the steps to follow to make the best use out of its features for your front-end applications.* If you can't wait to dive straight into Prepr, follow the [Quick start guide](/quick-start-guide) to get your feet wet. Learn more about the structure of your Prepr project and then move on to the step-by-step guide to set it up. Looking for something specific? Check out the detailed resources below. Source: https://docs.prepr.io/project-setup --- # Content modeling *Explore the resources below to get started with content modeling and learn how to set up a well-defined schema in Prepr CMS.* Before diving into Prepr, learn the basics about content modeling and how to model content using some typical examples like a *Blog*, *Page* and *Personalization*. Dive into Prepr and learn how to set up a schema by managing models, components, setting up remote sources and other more advanced features. Source: https://docs.prepr.io/content-modeling --- # Connecting a front-end framework The flexibility of a data-driven headless CMS allows you to connect your favorite front-end framework, deliver content and optimize and personalize the visitor journey. Source: https://docs.prepr.io/connecting-a-front-end-framework --- # Developing with Prepr CMS *Discover everything you need to know to develop with Prepr CMS, including resources for connecting front-end frameworks, best practices, managing CI/CD pipelines and integration guides.* Source: https://docs.prepr.io/development --- # Content management Discover all you need to know about managing content items, how to handle assets, localizing content, and collaboration when working with content items in Prepr CMS. Source: https://docs.prepr.io/content-management --- # Data collection *Prepr CMS offers several data-driven features such as Adaptive content, A/B testing, and Recommendations. To power these features, Prepr requires visitor data. This data is essential for creating segments for personalization, evaluating A/B test results, and determining relevant recommendations. Discover all you need to know about collecting and managing visitor data to make the most out of these features.* Learn more about data collection key concepts and move on to the step-by-step guide to set it up. Looking for something specific? Check out the detailed resources below. Source: https://docs.prepr.io/data-collection --- # Personalization *Discover all you need to know about making your website adaptive by setting up personalization, managing segments and creating adaptive content to improve engagement and user experience.* Source: https://docs.prepr.io/personalization --- # A/B testing *Discover all you need to know about setting up and using Prepr CMS A/B testing to improve engagement and user experience.* Source: https://docs.prepr.io/ab-testing --- # Setting up recommendations Estimated duration: 15-30 minutes ## Introduction Prepr allows you to add recommendations to your web application quickly. This tutorial demonstrates how to deliver recommendations using the Prepr GraphQL API. Follow the step-by-step guide below. ## Use case Deliver highly relevant content recommendations to the visitors of your websites and apps using the GraphQL API to increase engagement. Let's examine an everyday use case: an article that you want to show recommendations for. Recommendations are usually displayed below an article to entice visitors to view more content. With Prepr, you can display three types of recommendations: - Similar items - People also viewed items - Popular items ### Similar items Similar items are recommendations similar to the article the visitor is currently viewing. Because it's on the same topic, or because it's by the same author, or maybe it's approximately the same length. With this recommendation type, the algorithm looks at the characteristics of the article (content, meta-data, links to other articles, etc.) and determines what the most relevant related articles are based on a score. ### People also viewed items People also viewed items are items that other visitors also viewed along with the item that a visitor is currently viewing. The algorithm looks at the current item and determines the visitors that viewed this item. It then lists the other items that these visitors also viewed. ### Popular items Popular items, the name says it all, are the most viewed items. The algorithm looks at how often an item has been viewed for this recommendation type. You could say this is not a recommendation but sorting by popularity. ### Content structure Before you start generating the recommendations, it’s a good idea to look at the content model of the article. That structure largely determines how accurate the recommendations become.  In this case you have an article with a number of content fields: title, intro and content. In addition, there are references to an author and to one or more categories. And finally, an editor can manually add tags. Prepr uses all this information to provide the most relevant recommendations. ## Creating a Prepr CMS account Following this guide requires a (free) Prepr CMS account. - Go to https://signup.prepr.io/ and sign up - Follow the [quick start guide](/quick-start-guide) to add models and content items ## Querying the API for similar items To retrieve similar items, you must first have the ID of the content item where you want to show recommendations for ### Getting a content item ID - Go to the **Content** tab and open the content item for which you want to retrieve similar items. - Click the icon and choose the **Copy item ID** option.  ### Retrieving similar items - Click the icon and choose the **Access tokens** option. - Click to open the *GraphQL Production* token details. - Click the **Open in API explorer** link.  View the API reference for all [API authentication details](/graphql-api/authorization) - Add the following query to the explorer: ```graphql copy query { Similar_Articles( id: "0cbe2455-124c-4820-b2ac-dcc4261e150c" ) { items { _id title } } } ``` - Replace the **id** value with the ID of your content item Note the **Similar\_Articles** query type at the beginning of the query. For each content model in your environment the Prepr creates a corresponding GraphQL type with a similarity algorithm. The plural type name of the content model is prefixed with Similar\_. For example Article generates a type Similar\_Articles. You can find all these options in the API Explorer. - Run the query The result should look something like: ```json copy { "data": { "Similar_Articles": { "items": [ { "_id": "885b71ac-5a4b-4d2e-9770-a4a6f20425e9", "title": "15 Tips On How To Brand Yourself Online" }, { "_id": "f1d9b142-883f-4964-8d8f-cd2f255330a2", "title": "Why Customization Is Key For Entrepreneurs In The Digital Age" }, { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design" }, { "_id": "79c453ed-ffe2-4aec-8fb2-f549e3775264", "title": "Building A Video Streaming App With Nuxt.js" }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time" }, { "_id": "ca0e0d37-600b-42f7-a013-9b0f8e18f127", "title": "The Evolution Of Jamstack" }, { "_id": "dd3309eb-df84-4e4b-8fdf-80b31b8eb58a", "title": "The Rise Of Design Thinking As A Problem Solving Strategy" }, { "_id": "f4b65d11-c2e2-4320-a363-e7d420d03ed2", "title": "Modeling A GraphQL API For Your Blog" } ] } } } ``` That's all. You now have recommendations that you can show in your application. Let's see how we can improve the recommendations even more. ### Filtering the result The previous example included all items for determining recommendations. But often, you want to make the result even more accurate. For example, you may want to query only recommended articles published recently or in a particular category. So let's see how you can do that. - Expand the query with the following parameters: ```graphql copy query { Similar_Articles( id: "0cbe2455-124c-4820-b2ac-dcc4261e150c" where: { _publish_on_gt: "2021-01-01T00:00:00+00:00" categories: { _slug_any: [ "ux-design", "development" ] } }, limit: 3 ) { items { _id title } } } ``` - We added **\_publish\_on\_gt**: "2021-01-01T00:00:00+00:00" to show only articles published after January 1, 2021. Note the underscore at the beginning of the parameter. - We added categories: **`{ _slug_any: [ "ux-design", "development" ] }`** to limit the result to only articles in the “UX Design” or the “Development” categories. Note the square brackets because we’re dealing with an array. - We added **limit: 3** to limit the number of results to three items The result should look something like: ```json copy { "data": { "Similar_Articles": { "items": [ { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design" }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time" }, { "_id": "dd3309eb-df84-4e4b-8fdf-80b31b8eb58a", "title": "The Rise Of Design Thinking As A Problem Solving Strategy" } ] } } } ``` View the API reference for [all filter options](/graphql-api/fetching-filtering-collections). ### Optimizing the recommendation algorithm The recommendation algorithm for similar items finds items based on the following criteria: |Criteria|Default weight|Description| |--------|----|------| |Topics |1.4| Highest weight. Topics are extracted automatically by the AI text analysis engine. It identifies specific people, places, or concepts within the item text and finds items with matching topics.| |Content References|1.2| Matches content items linked to the main item through any content references whether in the *Stack*, *Component* or *Dynamic content* field. For example, articles in the same category and articles by the same author.| |Tags|0.8| Matches items based on tag values in the main content item.| You can tweak the default logic to align with your own business priorities. For example, if your content items are related more by their common tags rather than linked items, you can increase the importance of *Tags*. Here’s an example of how that works: ```graphql copy query { Similar_Articles( id: "0cbe2455-124c-4820-b2ac-dcc4261e150c" where: { _publish_on_gt: "2021-01-01T00:00:00+00:00" categories: { _slug_any: [ "ux-design", "development" ] } }, limit: 3 rules: { entities: 0 tags: 1 references: 0.5 } ) { items { _id title } } } ``` - We added rules: **`{ entities: 0, tags: 1, references: 0.5 }`** to indicate that topics should not be included and that the tag criteria has higher priority than references. We recommend starting with the default setting and adding rules only if the result does not meet your expectations. View the [API reference](/graphql-api/personalization-recommedations-similar-content) for all rules options. ## Querying the API for People Also Viewed items To retrieve *People also viewed* items, you need the ID of the content item that you want to show recommendations for. ### Getting a content item ID - Go to the **Content** tab and open the content item you want to use as the reference. - Click the icon and choose the **Copy item ID** option.  Now that you have the *Content Item ID*, you can track visitors who viewed the same content item. That information can be used to display the *People Also Viewed* items. ### Capturing views You can capture view events in Prepr using a lightweight piece of JavaScript, the *Prepr Tracking Code*. Follow the steps in the [Tracking setup guide](/data-collection/setting-up-the-tracking-code#enabling-prepr-tracking) to add the *Prepr Tracking Code*. Once you've enabled tracking, you can then [add a meta tag](/data-collection/recording-events#tracking-content-items) to record view events on content items. Check out the [Events doc](/data-collection/recording-events) for all tracking options. ### Retrieving People also viewed items Now that you’re tracking the visitors that view an item, you can retrieve the other items that these visitors also viewed. - Click the icon and choose the **Access tokens** option to view all the access token. - Click to open the *GraphQL Production* token details. - Click the **Open in API explorer** link.  View the API reference for all [API authentication details](/graphql-api/authorization) - Add the following query to the explorer: ```graphql copy query { PeopleAlsoViewed_Articles ( id : "90276002-d628-4ba6-b3c8-f756c486b67b" ) { items { _id, title } } } ``` Note the **PeopleAlsoViewed\_Articles** query type at the beginning of the query. Prepr automatically provides you with a `PeopleAlsoViewed` query for each model. For example, if your model name is Article, you also get the PeopleAlsoViewed\_Articles query. You can find all these query options in the API Explorer. The result should look something like this: ```json copy { "data": { "PeopleAlsoViewed_Articles": { "items": [ { "_id": "0cbe2455-124c-4820-b2ac-dcc4261e150c", "title": "How to set up a Google Ads account" }, { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design" }, { "_id": "79c453ed-ffe2-4aec-8fb2-f549e3775264", "title": "Building A Video Streaming App With Nuxt.js" }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time" }, { "_id": "dd3309eb-df84-4e4b-8fdf-80b31b8eb58a", "title": "The Rise Of Design Thinking As A Problem Solving Strategy" }, { "_id": "f1d9b142-883f-4964-8d8f-cd2f255330a2", "title": "Why Customization Is Key For Entrepreneurs In The Digital Age" }, { "_id": "885b71ac-5a4b-4d2e-9770-a4a6f20425e9", "title": "15 Tips On How To Brand Yourself Online" }, { "_id": "ca0e0d37-600b-42f7-a013-9b0f8e18f127", "title": "The Evolution Of Jamstack" }, { "_id": "f4b65d11-c2e2-4320-a363-e7d420d03ed2", "title": "Modeling A GraphQL API For Your Blog" } ] } } } ``` ### Filtering the result The previous example includes all items that other users viewed. But often, you want to make the result even more accurate. For example, only show items published recently or in a particular category. So let's see how you can do that. - Expand the query with the following parameters: ```graphql copy query { PeopleAlsoViewed_Articles( id : "90276002-d628-4ba6-b3c8-f756c486b67b", where: { _publish_on_gt: "2021-01-01T00:00:00+00:00" categories: { _slug_any: [ "ux-design", "development" ] } }, limit: 3 ){ items { _id title } } } ``` - We added `_publish_on_gt: "2021-01-01T00:00:00+00:00"` to show only articles published after January 1, 2021. Note the underscore at the beginning of the parameter. - We added categories: `{ _slug_any: [ "ux-design", "development" ] }` to limit the result to only articles in the “UX Design” or the “Development” categories. Note the square brackets because you’re dealing with an array. - We added `limit: 3` to limit the number of results to three items. Result: ```json copy { "data": { "PeopleAlsoViewed_Articles": { "items": [ { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design" }, { "_id": "79c453ed-ffe2-4aec-8fb2-f549e3775264", "title": "Building A Video Streaming App With Nuxt.js" }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time" } ] } } } ``` ## Querying the API for most popular items To show the most popular items, you must track how often visitors view content items. That information can be used to display the most popular items. ### Capturing views You can capture view events in Prepr using a lightweight piece of JavaScript, the *Prepr Tracking Code*. Follow the steps in the [Tracking setup guide](/data-collection/setting-up-the-tracking-code#enabling-prepr-tracking) to add the *Prepr Tracking Code*. Once you've enabled tracking, you can then [add a meta tag](/data-collection/recording-events#tracking-content-items) to record view events on content items. Check out the [Events doc](/data-collection/recording-events) for all tracking options. ### Retrieving most popular items Now that you’re tracking how often visitors view an item, you can retrieve the most popular items. - Click the icon and choose the **Access tokens** option. - Click to open the *GraphQL Production* token details. - Click the **Open in API Explorer** link.  View the API reference for all [API authentication details](/graphql-api/authorization) - Add the following query to the explorer: ```graphql copy query { Popular_Articles { items { _id title _views } } } ``` Note the **Popular\_Articles** query type at the beginning of the query. Prepr automatically provides you with a popularity query for each model. If your model name is Article, you also get the Popular\_Articles query. You can find all these query options in the API Explorer. Note the **\_views** system field that shows the number of views for a content item. This field is optional. We recommend not using it to optimize cache efficiency. The result should look something like this: ```json copy { "data": { "Popular_Articles": { "items": [ { "_id": "0cbe2455-124c-4820-b2ac-dcc4261e150c", "title": "How to set up a Google Ads account", "_views": 83 }, { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design", "_views": 59 }, { "_id": "79c453ed-ffe2-4aec-8fb2-f549e3775264", "title": "Building A Video Streaming App With Nuxt.js", "_views": 49 }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time", "_views": 40 }, { "_id": "dd3309eb-df84-4e4b-8fdf-80b31b8eb58a", "title": "The Rise Of Design Thinking As A Problem Solving Strategy", "_views": 29 }, { "_id": "f1d9b142-883f-4964-8d8f-cd2f255330a2", "title": "Why Customization Is Key For Entrepreneurs In The Digital Age", "_views": 21 }, { "_id": "885b71ac-5a4b-4d2e-9770-a4a6f20425e9", "title": "15 Tips On How To Brand Yourself Online", "_views": 11 }, { "_id": "ca0e0d37-600b-42f7-a013-9b0f8e18f127", "title": "The Evolution Of Jamstack", "_views": 9 }, { "_id": "f4b65d11-c2e2-4320-a363-e7d420d03ed2", "title": "Modeling A GraphQL API For Your Blog", "_views": 5 } ] } } } ``` ### Filtering the result The previous example included all items for retrieving the most popular items. But often, you want to make the result even more accurate. For example, only show items published recently or in a particular category. So let's see how you can do that. - Expand the query with the following parameters: ```graphql copy query { Popular_Articles( where: { _publish_on_gt: "2021-01-01T00:00:00+00:00" categories: { _slug_any: [ "ux-design", "development" ] } }, limit: 3 ) { items { _id title _views } } } ``` - We added `_publish_on_gt: "2021-01-01T00:00:00+00:00"` to show only articles published after January 1, 2021. Note the underscore at the beginning of the parameter. - We added categories: **`{ _slug_any: [ "ux-design", "development" ] }`** to limit the result to only articles in the “UX Design” or the “Development” categories. Note the square brackets because you’re dealing with an array. - We added `limit: 3` to limit the number of results to three items. Result: ```json copy { "data": { "Popular_Articles": { "items": [ { "_id": "dd42b8c4-4773-4fdd-a71f-87e57b35beaa", "title": "Building User Trust In UX Design", "_views": 59 }, { "_id": "79c453ed-ffe2-4aec-8fb2-f549e3775264", "title": "Building A Video Streaming App With Nuxt.js", "_views": 49 }, { "_id": "5a53b271-898e-4eef-b877-5863b34b6ff9", "title": "UI Design Testing Tools I Use All The Time", "_views": 40 } ] } } } ``` ## Want to learn more? Check out the following chapters: - [A/B testing](/ab-testing/setting-up-ab-testing) - [Personalization](/personalization/setting-up-personalization) ## Schedule a free consultation Do you want to get started with recommendations but still have questions or want a demo? [Schedule a free call](https://prepr.io/get-a-demo) with a Prepr solution engineer. Source: https://docs.prepr.io/recommendations --- # Integrations Extend Prepr CMS with one of the standard integrations listed below. If you need to build a custom integration, check out the [creating a custom remote source](/content-modeling/creating-a-custom-remote-source) or [using webhooks](/development/best-practices/webhooks) resources instead. Source: https://docs.prepr.io/integrations --- # AI-friendly documentation *From this guide, you'll learn how to use Prepr's machine-readable documentation formats with AI coding assistants for faster, more accurate development.* ## Introduction Prepr's documentation is available in LLM-friendly formats that make it easy to integrate with AI coding assistants like Claude, ChatGPT, Cursor, and GitHub Copilot. These formats follow the [llms.txt](https://llmstxt.org/) standard, providing machine-readable documentation that AI assistants can use as context when helping you build with Prepr. By adding Prepr documentation to your AI assistant, you'll get: - Accurate answers based on the latest Prepr documentation - Code suggestions that follow Prepr best practices - Faster development with context-aware assistance - Reduced errors from outdated or incorrect information ## Available formats Prepr documentation is available in three LLM-friendly formats: ### llms.txt The `llms.txt` file provides an index of all documentation pages with titles and descriptions. **URL:** **Best for:** Quick reference and helping AI assistants find relevant documentation sections. ### llms-full.txt The `llms-full.txt` file contains the complete Prepr documentation in a single, machine-readable text file. **URL:** **Best for:** Providing full context to AI assistants for comprehensive answers about Prepr. ### Markdown format (.md) Any documentation page can be accessed in markdown format by appending `.md` to the URL. **Example:** **Best for:** Getting the raw markdown content of individual pages for focused context. ## Using with AI ## Tips for using AI assistants with Prepr Source: https://docs.prepr.io/ai-friendly-docs --- # Prepr MCP server *From this guide, you'll learn how to set up the Prepr MCP (Model Context Protocol) to help editors manage content from an AI agent or built-in AI tools, like Notion AI.* ## Introduction Connect AI clients to your Prepr environment with a [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/intro) server at `https://mcp.prepr.io/mcp`. The Prepr MCP server helps editors and teams find content, create and update localized items, review publication state, update workflow, assign work, patch supported fields, and publish or unpublish items directly from AI tools. ## The Prepr MCP server (Beta release) The Prepr MCP server gives AI clients a safe, structured way to work with content in your Prepr environment. With the MCP server, an AI client can trigger the following actions: - Search for content items across your environment - Search for assets such as images, videos, audio, and documents - Upload an image or document asset from a public URL or file path - Fetch an item with a matching *Content item ID* - Create a new localized content item - Update an existing localized content item - Publish items now or schedule publishing for later - Unpublish items - Change workflow stages - Assign or unassign items - Add comments to content items - Patch supported root fields - Delete an item or a specific locale with explicit confirmation ## Connecting to the Prepr MCP server To connect the Prepr MCP server, follow the steps below. 1. [Request a Prepr MCP token](mailto:support@prepr.io?subject=Request%20Prepr%20MCP%20token) with the permissions you want the AI client to have. 2. Add a remote MCP server to your client. 3. For example, in Notion, click the **+ New agent** menu item and enter a description like *Creates and updates Prepr CMS content items from Notion pages, sets the requested stage and assigns them to a user.* Once created, go to the **Settings**, add a connection and choose to add a custom MCP.  4. Set the server URL to `https://mcp.prepr.io/mcp`. 5. Pass your token in the `Authorization` header. ## Safety and limitations The MCP is designed to help with editorial work, but write actions still need the right context. Important behavior: - Write actions depend on your Prepr MCP token permissions - If you're connecting to a multi-locale environment, the AI agent should ask for clarification when it's not clear which locale to create or update a content item - For a single-locale environment, include the locale in the AI agent's core instructions. - If multiple candidate items match the request, the AI agent should ask for clarification before mutating content - Deleting content always requires explicit confirmation Current limitations: - The `create_item` request creates one locale per call and supports model-level root fields of type `Text`, `Boolean`, `Integer`, `Float`, `Enum`, `Color`, `Tags`, `ContentReference`, `Asset`, and `ElementBox` - If you only have a public image or document URL, the model can first use `upload_asset` and then use the returned asset ID in an `Asset` field or dynamic content block - The `update_item` request uses the same simplified input shape as `create_item`, but sends a full `PUT` update for one locale after first merging your changes into the current item - The `patch_items` request supports model-level root fields of type `Text`, `Boolean`, `Integer`, `Float`, `Enum`, `Color`, `Tags`, and `ContentReference` - The bulk mutation calls are processed in chunks of up to `25` content item IDs per call ## Currently known bugs and PR’s - Resource needs to be added with payload examples for the dynamic content editor - Stack field is not yet supported when creating or updating content items. Source: https://docs.prepr.io/prepr-mcp --- # Prepr schema spec *From this guide, you'll learn how to use the Prepr schema spec to generate and validate schema JSON files you can import into your Prepr schema.* ## Introduction The Prepr schema specification is a standardized format (in JSON) that defines the structure, relationships, and rules of Prepr schema elements: *Models*, *Components*, *Enumerations*, and *Remote Sources*. You can use this spec to validate manually created schema JSON files by running the [Prepr schema validation](/development/working-with-cicd/validating-a-schema). You can also potentially use the Prepr schema spec to give additional context to an AI agent or a development tool if you wish to generate a Prepr schema automatically based on your UX design and instructions. We’re excited to see how AI can accelerate the way you design your Prepr schema. ## Generate a Prepr schema (Experimental) To automatically generate a Prepr schema using your preferred AI agent or development tool, perform the steps below. 1. Download the spec from our [Validation GitHub repo](https://github.com/preprio/action-schema-validation/blob/main/spec/2026-03-05.json5). 2. Upload the spec to your LLM and provide your project requirements. 3. Continue prompting to tweak fields and relationships. 4. Once the schema JSON files are generated, follow the steps in the [validation guide](/development/working-with-cicd/validating-a-schema) to upload them into a GitHub repo and validate them before importing them into your Prepr environment. Source: https://docs.prepr.io/schema-spec --- # AI text assistant features *This article details the setup of the available AI assistant features for creating, editing and reviewing text in content items.* ## Introduction Learn how to set up the following AI text assistant features to support editors with creating, updating and reviewing content: - AI translation - AI text generation - AI text optimization - AI check for SEO values ## Translating content items Content editors can automatically create high-quality first drafts of content items in a chosen language using AI.  This feature lightens the workload for content editors who need to create translated copies of a content item. This AI feature is enabled by default for all models and all text fields. To disable AI translation for specific fields, follow the steps below. 1. In the **Schema** page, choose the model you want to update. 2. Click the applicable field to open the *Settings*, and go to the **AI** tab.  3. Switch off the **Allow this field to be translated using AI** toggle. Now when a content editor translates a content item for this model, this field will not be translated, but simply copied to the new language version. ## Generating text Content editors can generate new text on request, for example, when they want to create an SEO title based on the main title of an article.  This feature makes it quicker and easier for content editors to create engaging text in their content. To enable AI text generation for specific fields, follow the steps below. 1. In the **Schema** page, choose the model you want to update. 2. Click to the applicable field to open the *Settings* and go to the **AI** tab.  3. Enable the **Allow AI text generation** toggle. 4. To set the prompt, it's easiest to choose one of the suggested prompts and adjust it for your own needs. Once done, content editors will see a **Generate text** link above the field they can auto-generate with AI. ## Optimizing text Content editors can use AI to improve existing text, for example, to make their text longer, shorter or simpler.  This feature makes it quicker and easier for content editors to create engaging text in their content. To enable AI text optimizing for specific fields, follow the steps below.  1. In the **Schema** page, choose the model you want to update. 2. Click to the applicable field to open the *Settings* and go to the **AI** tab.  2. Enable the **Allow AI optimizing** toggle. 3. You can select or deselect one or more of the predefined actions a content editor is allowed to choose when optimizing the text: - Improve writing - Fix spelling and grammar - Make shorter - Make longer - Simplify language Once done, content editors will see the **Ask AI** action when hovering over the enabled field. ## Checking SEO values The [*Content check*](/content-management/reviewing-content#content-check) feature automatically checks a content item for nonoptimal SEO values and makes suggestions you can choose to apply or ignore.  The *Content check* feature is enabled by default when you create a model. It makes the icon available when editing a content item. To disable this feature, follow the steps below. 1. Go to the **Schema** tab and choose the model you want to update. 2. Open the applicable model where you don't want content editors to use the *Content check* feature. 3. Click the **Settings** button to open the model settings.  4. Go to the **Features** tab and switch off the **Content check** toggle and click the **Save** button. Now, content editors won't see the action when they open a content item for this model. Source: https://docs.prepr.io/ai-text-assistant --- # AI suggestions for adaptive content *This article explains how to set up the AI assistant to generate suggestions for adaptive (personalized) content.* ## Introduction When adding personalized content, editors and marketers can get AI suggestions for adaptive content based on a customer segment they choose. The auto-generated variant suggestions gives them inspiration to quickly create and fine-tune their adaptive content. ## Setting up AI assistant to generate suggestions To set up the AI assistant to allow editors and marketers to generate suggestions for adaptive content, follow the steps below. 1. Define context for AI requests in your [environment settings](/project-setup/setting-up-environments#define-environment-context-for-ai-requests).  2. Define additional context in each [segment](/personalization/managing-segments#defining-segment-context).  The AI icon is available by default in an adaptive content section. Once all the relevant context is defined, editors can [AI-generate suggestions for adaptive content](/personalization/managing-adaptive-content#generate-ai-personalized-variants).  If you have any questions, please [contact our Support team](https://prepr.io/support). Source: https://docs.prepr.io/ai-suggestions-adaptive-content --- # AI-generated text for images *This AI integration automatically generates text values, such as alt text, when uploading new images.* ## Introduction When you activate the *Prepr image processing* integration, you can choose to integrate to AI to process images. When a user uploads an image, Prepr CMS prompts AI to scan the image and the image file name to detect information and generate selected text values, such as alt text. ## Activate AI generation for image text fields Simply activate the AI integration with the following steps: 1. Click the icon and choose the **Integrations** option to view all integrations. Go to the **Prepr image processing** card and click the **Activate** button.  2. Enable the **AI** toggle and choose one or more of the fields listed. - **Internal name** - **Description** - **Custom asset fields** - These include any custom text fields you added to the [*Asset* model](/content-modeling/defining-the-asset-model#add-fields-to-the-asset-model), like an *Alt text* field. To make changes to the options, go back to the **Prepr image processing** card and click the **Manage** button to make your changes. 3. If you have any custom asset fields in the *Asset* model, set a prompt for each text field you want AI-generated, as follows: - Go to the **Schema** page and click to open the **Asset** model. - Click the text field you want AI-generated and in the dialog, click the *AI* tab. - Then enable the toggle to **Allow AI text generation** - Choose one of the *Suggested prompts* and edit it, if needed, or create your own and click the **Save** button. Once the AI integration is activated and all prompts are set, editors will get generated text for any new images they upload.  If you have any questions, please [contact our Support team](https://prepr.io/support). Source: https://docs.prepr.io/ai-image-text --- # The Prepr Next.js package *The Prepr Next.js package offers some helper functions and the Prepr preview toolbar for easier personalization and A/B testing implementation. This guide introduces you to the *Prepr Next.js package* and shows you how to use it.* ## Prerequisites - You need to have a [Next.js project connected to Prepr](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic#connect-your-nextjs-website-to-prepr) before installing the package. ## Introduction The *Prepr Next.js* package includes the following features: - It provides API request headers for the following values: - Each visitor's ID. You need this API request header, `Prepr-Customer-Id`, when you query adaptive content and content with A/B testing. - Any UTM parameters, if applicable. This is useful to identify visitors who enter your website through a social media campaign, for example. - HubSpot cookie, if it exists. This is useful for identifying visitors who are tracked in HubSpot as a lead, for example. - The visitor's IP address. This is useful for localization. - The Prepr preview toolbar includes the following features: - Provides an easy way to test adaptive content and content with A/B test variants - Allows content editors to edit content through a link from the preview page.  - The package also allows you to enable Visual editing in your Prepr environment. Check out the [visual editing guide](https://docs.prepr.io/project-setup/setting-up-visual-editing#nextjs) for more details. - The package auto detects stega-encoding to prevent misaligned layout elements in the preview version of the web app. For additional implementation options and technical details, check out the [Prepr Next.js package repo](https://github.com/preprio/prepr-nextjs) directly in GitHub. ## Installation To install the *Prepr Next.js package,* follow the steps below. 1. Run the following command in your Next.js project: ```bash copy npm install @preprio/prepr-nextjs ``` 2. Add the `PREPR_ENV` variable to the `.env` file. You can enable the Prepr preview toolbar for a staging environment by setting the value to `preview`. ```bash copy filename="./.env" {2} PREPR_GRAPHQL_URL=Some bold text and italic
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
", "format": null } } } } ``` ### Dynamic content The Dynamic content field contains embedded videos, social media posts, maps, assets, and components for rich content items like in the example request below. ```json copy { "items": { "en-US": { // The content item entry for this locale. "content": { // The API Id of the dynamic content field "items": [ { // Embedded heading text in the dynamic content field "id": "aa82833a-7b0c-413c-b8e5-e463efb32903", "created_on": "2023-09-27T15:05:25+00:00", "changed_on": null, "label": "Text", "body": "Ingredients", "format": "H2" }, { // Embedded bullet points in the dynamic content field "id": "d0ea8c21-0826-46ee-b559-3fb838daa1c7", "created_on": "2023-09-27T15:05:25+00:00", "changed_on": null, "label": "Text", "body": "| Pros | Cons |
| Tasty | Lots of calories |
| Easy to make | Need to use the oven |
| Pros | Cons |
| Tasty | Lots of calories |
| Easy to make | Need to use the oven |
Whether it's for a brunch, dinner or tea party, quiche is the perfect addition and can be extremely easy to prepare and customize to suit your and your guests' taste buds.
" }, // The API Id of a single line Text field "title": { "body": "Say quiche" } } } } ``` ## Update a content item To update an existing content item, send a `PUT` request to the `https://mutation.prepr.io/content_items/{id}` endpoint. Replace `{id}` with the Id of the content item to be updated. Make sure the `Content-Type` in the header is set to `application/json` to send a valid JSON body. Keep the following in mind when you create your update request: - Prepr doesn't merge content changes but completely updates a content item for a locale. So you must send the entire body for each locale that you want to update. - When updating one locale, any other locales that are not in the update request remain unchanged. - It's possible to update the `workflow_stage` of a locale without sending the items array. See an example below of an update to the workflow stage of an existing *Article* content item. ```json copy { "locales": [ "en-US" ], "workflow_stage": { // Update workflow stage to review "en-US": "Review" }, "assigned_to": { // Assign to a user to do the review "en-US": { "id": "1f71ff0a-f1f9-4cc3-85b4-bb8c7e33e4e0" // The Id of the existing user in this Prepr environment } } } ``` ## Patch a content item To only update specific fields on an existing content item, send a `PATCH` request to the `https://mutation.prepr.io/content_items/{id}` endpoint. Replace `{id}` with the Id of the content item to be updated. Make sure the `Content-Type` in the header is set to `application/json` to send a valid JSON body. Keep the following in mind when you create your patch request: - Only supported field types on the model level can be updated by the patch endpoint. - The updates done by the patch endpoint will not update the `changed_on` metadata of an item. The update is processed silently and doest effect the order when sorting on `changed_on`. - Field will be patched at root level, for example, if an Asset field is patched, you need to pass the full field content. - The `PATCH` will update the latest version of an item, if this version is currently a DRAFT the update will be published when the editor publishes the new version. If the version is already PUBLISHED, changes will be live immediately. - Webhook events are triggered the same as with standard updates. - Required fields will not trigger validation rules. See an example below of an update to the title of an existing *Post* content item. ```json copy { "locales": [ "en-US" ], "slug": { "en-US": "a-new-post-title" }, "items": { "en-US" : { "title" : { "body" : "A new Post title" } } } } ``` The `PATCH` request supports the following field types: `Slug`, `Text`, `Enum`, `Color`, `Boolean`, `Integer`, `Float`, `Coordinates`, `Content reference`, `Asset`, `Date & Time` (single only), `Social`, `Form Embeds`, `Resource`, `Tag` ## Field types The list of field types in the `items` array of a content item depends on the related model. In the example `POST` requests above, you can see that the `api_id` of a field is used to list the field array in `items`. Go to **Schema → Model → Field type settings** to get the `api_id` of the fields that you want to include in the mutation request. For a full list of field types and available settings like validation rules, check out the [Schema field types doc](/content-modeling/field-types) for more details. Here is a list of field types that you might need to set up when you create or update a content item. ### Text The Text field can be a single line, multiple lines, or HTML. Set the `body` values like in the example request below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // API Id of a single line text field "title": { "body": "Headline" }, // API Id of a text area field with multiple lines "my_text_area": { "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi u" }, // API Id of an HTML text field "my_html_text": { "body": "Some bold text and italic
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
" } } } } ``` ### List (Enum) The List field is a simple string with the content of the field. The content should match one of the values in the linked Enumeration. Set the values like in the example request below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // API Id of a List field "align": { "body": "left" } } } } ``` ### Dynamic content Embed rich text, videos, social media posts, maps, and assets in this field to create rich content items like the [*Article* request example](#article-example). Below is a list of elements that you can embed in the dynamic content field. | Embedded element | Label | DESCRIPTION | |------------------|---------|-----------------------------------------------| | Text | `Text` | | | Asset| `Asset`| Use an `items` object to embed an asset and set the `id` to an existing asset in Prepr like in the example above.| | Location | `Coordinates` | Set the `latitude` and `longitude` values to embed a location. | Check out the [Remote content](#remote-content) and [Social](#remote-content) field type details to embed these in your dynamic content field. ### Assets Assets are images, videos, and audio files or documents that you can link to a content item. Set the `id` value to an existing asset in your Prepr environment like the example below. Check out the [Managing assets doc](/mutation-api/assets-upload-update-and-destroy) on how to upload assets using the REST API. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { //API Id of the Asset field "cover": { "items": [ { // An Id of the asset that already exists in Prepr "id": "d7261363-a656-4b8e-bc39-506e6d6ab365" } ] } } } } ``` ### Integer Set an integer to store stock quantities, prices in cents, etc. like in the example below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the Integer field "quantity": { // The number value "value" : 122 } } } } ``` ### Float Set number entries with decimal places, for a price of an item, distance, or weight, etc. like in the example below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { //The API Id of the Integer field "quantity": { // The number value with decimal points "value" : 122.22 } } } } ``` ### Boolean Set a boolean field to true or false like in the example below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the boolean field "needs_social_post": { "value": true }, } } } ``` ### Stack The Stack field includes a list of (personalized) models/components. Check out the [stack field docs](/content-modeling/field-types#stack-field) for more details. In the example below, you can see a request for a *Page* content item. Check out the related *Page* model on a Prepr environment with Demo data or create a model from the *Page* template. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of a stack field "stack": { // This element contains all components and items in the stack "items": [ { // Items object of a Page header component "items": { // The API Id of a text field in the component "cta_label": { "body": "Let's get baking!" }, // The API Id of a text field in the component "heading": { "body": "Welcome to our baking community" }, // The API Id of an asset field in the component "image": { "items": [ { // The Id of an existing image in this Prepr environment "id": "cf91df18-df0e-4a20-b84a-8ef448becef9" } ] }, // The API Id of a text field in the component "text": { "body": "Learn some basic steps to get started or kick your skills up a notch with our handy tips, recipes and products." } }, // Component Id of the page header component "id": "bc2c106b-9e9d-43a8-b8c4-8d72866a9b4b", }, { // Items object of a Image and Text component "items": { "image": { "items": [ { // The Id of an existing image in this Prepr environment "id": "6059ecee-270f-46b0-b286-2e3e9374d33a" } ] }, // The API Id of a List field "image_position": { "body": "Left" }, "text": { "body": "Everyone has their own way to crack an egg. Maybe they learnt it from a parent or from watching cooking videos. The truth is there is no \"best\" way. Practice makes perfect. Start with the back of a knife or fork and try not to get any shell pieces into your egg." }, "title": { "body": "The best way to crack an egg" } }, // The component Id for the image and text component "id": "906ac62d-b59d-4346-ac7f-bf10a92fbb22", }, { // Link to an existing Call to action content item "id": "51898d57-f507-475f-bc6b-7dc3405bbed5" } ] }, // The API Id of a text field in the content item "title": { "body": "Home page" } } } } ``` ### Content reference The Content reference field stores a link to one or more content items. Check out an Article example below with a content reference to a *Person* content item to link authors. ```json copy { "model": { // The Id of the Article model "id": "b2298bbf-eda1-4f5c-9648-9213ecef6746" }, "locales": [ "en-US" ], "workflow_stage": { "en-US": "In progress" }, "items": { "en-US": { // The API Id of the Content reference field // for linked Person content items "authors": { "items": [ { // The Id of an existing Person content item "id": "54515b1a-b6d6-4002-956a-39d809023921" } ] }, "title": { "body": "Say quiche" } } } } ``` ### Component Components are often used to represent a set of reusable fields. Also, it can be added as a custom element to the Dynamic content or Stack fields. In the example below we have an *Article* content item that has an *SEO* component. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the component field "seo": { // The list of fields based on the SEO component "items": { // The API Id of a text field in the component "description": { "body": "An easy french toast recipe" }, // The API Id of an asset field in the component "social_media_image": { "items": [ { // The Id of an existing asset in this Prepr environment "id": "6059ecee-270f-46b0-b286-2e3e9374d33a" } ] }, // The API Id of a text field in the component "title": { "body": "The easiest french toast recipe" } }, // The component Id for the embedded component "id": "906ac62d-b59d-4346-ac7f-bf10a92fbb22" } } } } ``` ### Remote content The Remote Source Response for a request with a Remote content field allows you to reference content in an external CMS, legacy system of eCommerce platform. [Check out the Remote source setup guide](/content-modeling/creating-a-custom-remote-source) to quickly setup your first integration. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the remote content field "kitchen_shop": { // The list of remote items for this content items "items": [ { // Id that matches the the item in the remote source "id": "2", // The main info about the item "body": "Spatula", "description": "We're willing to bet you reach for your spatula more often than you think. This tool is ideal for flipping the perfect pancake", // The URL where the image is stored "image_url": "https://prepr-example-show-content-demo-patterns.stream.prepr.io/w_1920,h_1080/2qanpdxyhf20-spatula.png", "content_integration": { // Id of the remote source from where the data will be synced "id": "c0263fe3-007e-4307-9792-7364f6c0cf06" } } ] } } } } ``` Content integration items in Prepr have a predefined schema. This means that the type for any content integration item in the REST API schema follows the definition above. ### Date & Time The DateTime field adheres to ISO 8601 standard. Check the field settings, to create or update this field correctly: - **The Type** - The structure of this field is different depending on the *Type*: *Date*, *Date range* or *Business hours*. - **Time selection** - When time selection is enabled, set the format to `Y-m-d H:i:s` instead of `Y-m-d`. - **Multiple dates** - When Allow extra dates is enabled, put the content in an `items` object like in the example below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // API Id of a date field "event_date": { // Date only format "format": "Y-m-d", "value": "2023-01-01" }, // API Id of a date time field "start_date_and_time" : { // Format with time selection "format": "Y-m-d H:i:s", "value": "2020-10-19 12:00:00" }, // API Id of a date range field "project_duration": { // Date only format "format": "Y-m-d", "from": "2023-01-01", "until": "2024-12-31" }, // API Id of a date time range field "event_duration": { // Format with time "format": "Y-m-d H:i:s", "from": "2023-01-01 00:00:00", "until": "2024-12-31 23:59:59" }, // The API Id of a date range field with multiple date ranges "seasons": { "items": [ { "from": "2023-12-01", "until": "2024-02-29", "format": "Y-m-d" }, { "from": "2023-09-01", "until": "2023-11-30", "format": "Y-m-d" } ] }, // API of a Date and time field for Business hours "opening_times": { // List of days and corresponding business hours "items" : [ { "state": "open", // Number for corresponding day, 2 = Tuesday "open_day" : 2, // Opening time in 24 hour format "open_time" : "08:00", "close_day" : 2, // Closing time in 24 hour format "close_time" : "19:00" }, { "state": "open", // Number for corresponding day, 3 = Wednesday, etc. "open_day": 3, // Opening time in 24 hours format "open_time": "08:00", "close_day": 3, // Closing time in 24 hour format "close_time": "19:00" }, { // Example of an exception to the regular opening hours: Closed on Xmas day "state": "closed", "open_day": 4, "close_day": 4, "valid_from": "2025-12-25", "valid_until": "2025-12-26" } ] } } } } ``` ### Location The Location field allows content editors to add Google Maps geo-points (coordinates or an address) to your content item. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the Location field "event_location": { // Latitude value in Google maps "latitude": "21.3137", // Longitude value in Google maps "longitude": "-157.806" } } } } ``` ### Social Embed social posts in content items by adding a social URL. Set the `url` to a valid URL depending on the platform of the post. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the Social field in the content item "cooking_posts": { "url": "https://twitter.com/CookingChannel/status/1059520829841661954" } } } } ``` ### Color Add a Color field, by setting the HEX code like in the example request below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the color field "border_color": { // The Hex color code "body": "#000000" } } } } ``` ### Tag Add tags (keywords) to your content item like in the example request below. ```json copy { "locales": [ "en-US" ], "items": { "en-US": { // The API Id of the Tags field in the content item "search_keywords": { // An items array with a list of tags "items": [ { "body": "awesome", }, { // Id of an existing tag "id": "3dbf4dbe-9c87-4bae-9b23-7ae685655ea1", }, { // slug of an existing tag "slug": "more-than-great", }, ] } } } } ``` Source: https://docs.prepr.io/mutation-api/content-items-create-update-and-destroy --- # Publish a single item To publish or schedule a content item, use the following endpoint: ```http copy PATCH: /content_items/{id}/{locale}/publish ``` Optionally a UNIX timestamp can be sent with the request to schedule the item to be published at a later time. ```json copy { // UNIX Timestamp "publish_on" : 2342321312 } ``` If the request is successful the API will return status code 200. This endpoint will trigger the `content_item.published` event. Source: https://docs.prepr.io/mutation-api/content-items-publish --- # Unpublish a single item To unpublish a published version of a content item, use the following endpoint: ```http copy PATCH: /content_items/{id}/{locale}/unpublish ``` If the request is successful the API will return status code 200. This endpoint will trigger the `content_item.unpublished` event. Source: https://docs.prepr.io/mutation-api/content-items-unpublish --- # Delete a single item There are two options to delete an existing content item. You can either delete a specific language variant for a content item or delete the content item as a whole. For both operations the scopes `content_items` and `content_items_delete` are required. ## Delete a language variant in the content item To delete a specific language variant for a locale in the existing content item, request the following endpoint with the HTTP `DELETE` method. ```http copy DELETE: /content_items/94c56d8a-c54e-4b46-9971-a83bf06dcf52/en-US ``` Replace the `UUID` and the `locale` with the content item ID and locale you want to delete. If the request is successful the API will return an empty response and status code 204. ## Delete the entire content item To delete the content item as a whole, request the following endpoint with the HTTP `DELETE` method. ```http copy DELETE: /content_items/94c56d8a-c54e-4b46-9971-a83bf06dcf52 ``` Replace the `UUID` with the content item ID you want to delete. If the request is successful the API will return an empty response and status code 204. Source: https://docs.prepr.io/mutation-api/content-items-deleting --- # Fetching assets Prepr stores all your digital assets in the Media Library (in Prepr: the Media tab), making it easy to access, view, and manage your assets. You can add, edit, download, or delete files whenever needed; categorize, search, and filter assets on multiple attributes to find the right one quickly. ## The Asset object ```json copy { "id": "df7c1544-bad0-4c9d-928f-0c9f684c9ceb", "created_on": "2023-06-13T14:35:54+00:00", "changed_on": "2023-06-13T14:35:54+00:00", "label": "Photo", "name": "Sed et augue non mi dapibus tincidunt sollicitudin vel leo", "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vel ornare massa. Ut vehicula commodo consequat.", "author": "Marc van Dam", "status": null, "reference_id": "dam-249387", "width": 1020, "height": 1020, "file_size": 228286, // File size in bytes. Value available for assets uploaded since 23 December 2025 "original_name": "sed-et-augue.jpg", "mime_type": "image/jpeg", "cdn_files": { "total": 1, "items": [ { "id": "bfaac48b-fb0d-4d12-84da-af8d65244c4b", "created_on": "2023-06-12T08:44:43+00:00", "label": "CdnFile", "file": "371apne44zy3.jpg", "url": "https://example.stream.prepr.io/{format}/371apne44zy3-5az.jpg" } ] }, // Additional fields in the Asset model for the default locale // Boolean field to mark an asset copyrighted "copyrighted" : true, "author_name": { "body" : "John Captura", //An HTML text field for Author name }, "price": 12.50, // Number field for price // Additional fields in the Asset model for other locales // Pass the localized param to get the fields for other locales "localized" : { "de-DE" : { "copyrighted" : true } } } ``` | FIELD | DESCRIPTION | |---------------|------------------------------------------------------| | id | Unique identifier for each item. | | created\_on | UTC time at which the asset was created/upload. | | changed\_on | UTC time at which the asset was last updated. | | label | Identifier for the object. | | name | Name of the asset. | | body | Description of the asset. | | reference\_id | Custom asset API ID. | | author | Optional name of the author. | | width | Width of the image of video. | | height | Height of the image of video. | | original\_name | Name of the uploaded file. | | mime\_type | Mime type of the original file. | | cdn\_files | Object containing an array of `items`, the url field can be used for media playback. | ## Query by ID Since IDs are unique in Prepr, you can find the asset you want using the id argument. Here is an example that demonstrates how to query an asset with the ID "535c1e-...": ```http copy GET: /assets/535c1e-4d52-4794-9136-71e28f2ce4c1 ``` Source: https://docs.prepr.io/mutation-api/fetching-single-assets --- # Fetching assets Prepr stores all your digital assets in the Media Library (in Prepr: the Media tab), making it easy to access, view, and manage your assets. You can add, edit, download, or delete files whenever needed; categorize, search, and filter assets on multiple attributes to find the right one quickly. ```http copy GET: /assets ``` ## Search Prepr assets can be searched on their title or text fields. ```http copy GET: /assets?q[0][fz]=Beach Club ``` ## Types Assets can be filtered on their type. Available options are: `Photo`, `Video`, `Audio`, `Document`. ## Tags Assets can be filtered on their tags. You can query the tag fields by using the `tags` argument. ## Content Item relation Assets can be filtered on their relation to content items. ## Collections Assets can be filtered on their relation to collections. You can query the collections fields by using the `collections` argument. ```http copy GET: /assets?collections[0][eq]={ID} ``` ## Query by Reference ID The *Reference ID* is useful for storing external asset Ids. For example, during the migration of assets from another system. Check out the [Migration doc](/project-setup/migrating-content) for more details. Here is an example that demonstrates how to query an asset with a *Reference ID* value. ```http copy GET: /assets?reference_id[0][eq]=123456 ``` # Sorting You can use the `sort` argument to order your query results in a particular order. ```json copy { "sort": "created_on" } ``` ## Sort by metadata fields It is possible to sort by the assets created, changed dates in either ascending or descending order. The current values for sorting those fields are `created_on`, `-created_on`, `changed_on`, `-changed_on`. ## Default ordering If you don't pass an explicit order value the returned assets will be ordered descending by asset changed on timestamp `-changed_on`. This means that the most recently changed asset will appear at the top of the list. Source: https://docs.prepr.io/mutation-api/fetching-multiple-assets --- # Managing assets Use the REST API to do bulk mutation of assets when the [Media library UI](/content-management/managing-assets/managing-assets) is not an efficient option. For example, to upload assets as part of a project to migrate content from a legacy system to Prepr CMS. Before calling a REST API endpoint to manage the assets, go to **Settings → Access tokens** to create an access token with *REST API scopes* defined below. If you already have an access token for a related mutation in the same workflow, for example, a content migration project, simply add the relevant *REST API scopes* to this access token. ## The Asset object When uploading or updating an asset, you can include some additional information about the asset in the body of your request like in the example below. ```json copy { "name": "Example cover image", // If the name is not filled, the API will use the file name in this field. "body": "This is an asset that I uploaded using REST API.", // A description for this asset. "author": "Image Designer", // The author of the asset. "reference_id": "12345678", // An external ID for the asset, for example an ID from a legacy system. "tags": { // Include a list of related keywords to find the asset easily // For each tag, set either the ID, body or slug "items": [ { "id": "3dbf4dbe-9c87-4bae-9b23-7ae685655ea1" // ID of an existing tag in Prepr }, { "body": "dynamic" // If this tag doesn't exist, it will automatically be created }, { "slug": "dynamic-page" // If this tag doesn't exist, it will automatically be created } ] } "collections": { // Add this asset to a collection of similar assets "items": [ { "id": "ebc7fd2c-2458-4f2f-b7f5-5487f63d412a", // ID of an existing collection. Check out the Collections doc for more details. } ] } } ``` ## Upload new files Add the *REST API scopes* `assets` and `assets_publish` to the access token. The event `asset.created` will be fired when a new asset is created. ### Upload Image + Document + Audio To upload documents, photos, audio files, or cover images, send a `POST` request to the `https://mutation.prepr.io/assets` endpoint. - If the files are available locally, add the `"source"` parameter to specify a file like in the example below. Make sure the `Content-Type` in the header is set to `multipart/form-data` to send a valid asset file. * If the assets are located on a different server, set the `url` parameter to the URL location of the file like in the example code below. In this case, make sure the `Content-Type` in the header is set to `application/json`. You can upload files up to 25MB using the `url` parameter. When the upload is successful an auto-generated ID of the new asset will be returned in the response of this request. This ID can then be used to fetch the asset if needed. ### Upload Video To upload videos follow the steps below to upload each video in chunks. Make sure to handle errors and resume the upload of any remaining chunks before finishing the upload of a video. #### Step 1: Split the video into chunks First split each video into 25MB (26214400 bytes) chunks using the bash command below. ```bash copy split -b25m {filename} ``` #### Step 2: Start an upload session Start a resumable upload by initializing a new asset object. To make a start request and create a video upload session, send a `POST` request to the `https://mutation.prepr.io/assets` endpoint. Set the parameters as shown in the example below. When the upload is started successfully an auto-generated ID of the new asset will be returned in the response of this request. This ID can then be used in the request to upload the chunks and finish the request. #### Step 3: Upload chunks Now that the upload session has started and you have chunks ready to upload, make a transfer request to upload each chunk in the order that they are split. To upload the first video chunk, send a `POST` request to the `https://mutation.prepr.io/assets/{id}/multipart` endpoint and set the parameters like in the example below. Replace `{id}` with the ID returned in the response of the previous request. #### Step 4: Complete the upload Once you upload all chunks, make a finish request to complete the upload, post the video, and queue it for asynchronous video-encoding. Send a `POST` request to the `https://mutation.prepr.io/assets/{id}/multipart` endpoint and set the parameters like in the example below. Replace `{id}` with the ID returned in the response of the [start session request](#step-2-start-an-upload-session). ## Update To update an existing asset, add the *REST API scopes* `assets` and `assets_publish` to the access token. Send a `PUT` request to the `https://mutation.prepr.io/assets/{id}` endpoint. The `asset.changed` event will be fired when the asset is changed. Source: https://docs.prepr.io/mutation-api/assets-upload-update-and-destroy --- # Delete a single asset To delete the asset, request the following endpoint with the HTTP `DELETE` method. The scopes `assets` and `assets_delete` are required. ```http copy DELETE: /assets/94c56d8a-c54e-4b46-9971-a83bf06dcf52 ``` Replace the `UUID` with the asset ID you want to delete. If the request is successful the API will return an empty response and status code 204. Source: https://docs.prepr.io/mutation-api/delete-single-asset --- # Asset Collections A Collection represents a set of media files grouped by specific attributes and includes all types of assets. It can be a collection of images, videos, documents or audio files. ## The Collection object ```json copy { "id": "df7c1544-bad0-4c9d-928f-0c9f684c9ceb", "created_on": "2023-06-13T14:35:54+00:00", "changed_on": "2023-06-13T14:35:54+00:00", "label": "Collection", "body": "Branding & backgrounds" } ``` | FIELD | DESCRIPTION | |---------------|------------------------------------------------------| | id | Unique identifier for each item. | | created\_on | UTC time at which the asset was created/upload. | | changed\_on | UTC time at which the asset was last updated. | | label | Identifier for the object. | | body | Name of the collection. | ## Create, update or destroy ### Create a new collection To create a collection. ```http copy POST: /collections ``` ### Update an existing collection To update a collection. ```http copy PUT: /collections/{id} ``` ### Destroy an existing collection To destroy a collection. ```http copy DELETE: /collections/{id} ``` ## Managing collections ### Add assets to a collection To add assets to an existing collection, use the example below. This process only adds new assets to the collection. If this collection already has assets, these remain in the collection unchanged and duplicate entries are simply ignored. ```json copy { "items" : [ { "id" : "234h-432847-x23498-763x4-324x234" // The Asset ID, you can add mulitple assets at once. }, { // "id" : "30f064f4-8acb-4ee9-9e79-81d7029cc0c7" } ] } ``` ```http copy POST: /collections/{id}/assets ``` ### Remove assets from a collection To remove assets from an existing collection, use the example below. ```json copy { "items" : [ { "id" : "234h-432847-x23498-763x4-324x234" // The Asset ID. } ] } ``` ```http copy DELETE: /collections/{id}/assets ``` ### Set a collection cover To set a cover of the collection. ```http copy POST: /collections/{id}/cover?id={assetId} ``` ## Scopes `collections`, `collections_publish`, `collections_delete` Source: https://docs.prepr.io/mutation-api/assets-collections --- # Resizing ## Introduction The Images API is a read-only API for delivering images to apps, websites and other touchpoints. The Images API is available via a global CDN. The server closest to the user serves all content, which minimizes latency and especially benefits mobile apps. Hosting content in multiple global data centres also improves the availability of content. You can request images in specific sizes and crops. Images are returned with a `cdn_files` field. This object returns a `url` param that you can use as a basis for resizing the image needed for your app. The URL contains a part that is returned as `{format}` you need to replace this with the desired format. | argument | type | required | description | |----------|-------------| -------------| -------------| | `w` | String | false | Defines the width. | | `h` | String | false | Defines the height. | | `q` | String | false | Defines the image quality. | | `c` | String | false | Defines the crop. Default: `centre`. Options: `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center`, `centre` | The format is constructed as `{option}_{value}` so if we would want to get the image in a 200px width form, `{format}` should be replaced with `w_200`. To simplify this it's possible to let the API construct those URLs for you. Just add them as an extra field in the `cdn_files` field. This extra field is called `resized`. ## Example We want a `landing` image of 232x232 and a `thumb` of 123x123. The fields are constructed as followed: ```http copy GET: /assets/{id}?fields=cdn_files{resized{landing.width(232).h(232),thumb.width(123).h(123)}} ``` Example response: ```json copy { // Particle response of /assets endpoint. "cdn_files": { "total": 1, "items": [ { "id": "bfaac48b-fb0d-4d12-84da-af8d65244c4b", "created_on": "2023-06-12T08:44:43+00:00", "label": "CdnFile", "file": "371apne44zy3.jpg", "url": "https://example.stream.prepr.io/{format}/371apne44zy3-5az.jpg" "resized": { "landing": "https://example.stream.prepr.io/w_232,h_232/371apne44zy3.jpg", "thumb": "https://example.stream.prepr.io/w_123,h_123/371apne44zy3.jpg" } } ] } } ``` This will add an extra param(s) to the object with the pre-rendered URL. It is possible to add up to 3 different formats into the request. Source: https://docs.prepr.io/mutation-api/assets-resizing --- # Managing asset lifecycles *This guide provides step-by-step instructions on managing asset lifecycles in Prepr with support for custom transcoding or streaming services. Available exclusively to enterprise plan customers.* ## The asset lifecycle The below stages make up the simple asset lifecycle. ## Integrating with external platforms The steps below shows you how to handle key events when integrating with external platforms. ## Adding a cover thumbnail You can use the standard mutation API `post` endpoint to add a cover to your asset. Check out the [Manage assets doc](/mutation-api/assets-upload-update-and-destroy#upload-new-files) for more details. Source: https://docs.prepr.io/mutation-api/assets-integration --- # Fetching segments Segmentation organizes visitors into specific groups based on shared characteristics or similar behavior that matter for your use cases. These groups represent different target audiences for your business, making it easier to deliver more relevant content and experiences to your web app visitors. ## The Segment object ```json copy { "id": "df7c1544-bad0-4c9d-928f-0c9f684c9ceb", "created_on": "2023-01-23T14:34:59+00:00", "changed_on": "2023-01-23T14:34:59+00:00", "label": "Segment", "body": "Marketing campaign YYY", "reference_id": "utm-source-google-ads", "query": "{\"viewed\":[{\"param\":\"Body\",\"publication_tags_in\":[\"google-ads\"]}]}" } ``` | FIELD | DESCRIPTION | |--------------|-------------------------------------------------------------| | id | Unique identifier for each item. | | created\_on | UTC time at which the segment was created. | | changed\_on | UTC time at which the segment was last updated. | | label | Identifier for the object. | | body | Name of the segment. | | reference\_id | Custom segment API ID. | | query | JSON of the segment conditions. | ## Fetching all segments ```http copy GET: https://mutation.prepr.io/segments ``` The pagination of the segments endpoint is identical to the [content items endpoints](/mutation-api/fetching-paginating-collections). ## Query by ID Since IDs are unique in Prepr, you can find the segment you want using the id argument. Here is an example that demonstrates how to query a segment with the ID "535c1e-...": ```http copy GET: https://mutation.prepr.io/segments/535c1e-4d52-4794-9136-71e28f2ce4c1 ``` Source: https://docs.prepr.io/mutation-api/segments --- # Fetching tags A *Tag* is a meaningful label you can assign to your content items, visitors and assets to differentiate between them while filtering. ## The Tag object ```json copy { "id": "df7c1544-bad0-4c9d-928f-0c9f684c9ceb", "created_on": "2023-01-23T14:34:59+00:00", "changed_on": "2023-01-23T14:34:59+00:00", "label": "Tag", "body": "Amsterdam", "slug": "amsterdam" } ``` | FIELD | DESCRIPTION | |------------|-------------------------------------------------------------| | id | Unique identifier for each item. | | created\_on | UTC time at which the segment was created. | | changed\_on | UTC time at which the segment was last updated. | | label | Identifier for the object. | | body | Name of the tag. | | slug | Custom tag API ID. | ## Fetching all tags ```http copy GET: /tags ``` The pagination of the tags endpoint is identical to the [content items endpoints](/mutation-api/fetching-paginating-collections). ## Query by ID Since IDs are unique in Prepr, you can find the tag you want using the id argument. Here is an example that demonstrates how to query a tag with the ID "535c1e-...": ```http copy GET: /tags/535c1e-4d52-4794-9136-71e28f2ce4c1 ``` ## Managing tags ### Fields | argument | type | required | description | | ------------- |-------------| -------------| -------------| | `body` | String | true | Defines the tag. | ```json copy { "body": "Dog" } ``` ### Create To create a tag. ```http copy POST: /tags ``` ### Update To update a tag. ```http copy PUT: /tags/{id} ``` ### Destroy To destroy a tag. ```http copy DELETE: /tags/{id} ``` ## Tag Groups ### Fetching all tag groups ```http copy GET: /tag_groups ``` ### Managing tag groups #### Fields | argument | type | required | description | |-----------|--------|----------|-------------------------------------------| | `body` | String | true | Defines the name of the tag group. | | `tags` | Object | false | Defines the tags inside of the tag group. | ```json copy { "body": "Taggroup 1", "tags": { "items": [ { "id": "00a92e60-24bd-4908-a36c-96268465111f", "body" : "Amsterdam" } ] } } ``` #### Create To create a tag group. ```http copy POST: /tag_groups ``` #### Update To update a tag group. ```http copy PUT: /tag_groups/{id} ``` #### Destroy To destroy a tag group. ```http copy DELETE: /tag_groups/{id} ``` Source: https://docs.prepr.io/mutation-api/tags --- # Fetching customers Customers are all persons who have interacted with your content. Meaning all persons who have read, clicked, shared, bookmarked, or commented on content items. A customer profile is created for each person. You can manage these profiles in Prepr. With this, we enable you to segment and personalize content for your customers. ## The Customer object To expand the customer object when querying a customer add the field name below in the `fields` parameter. ```json copy { "id" : "234h-432847-x23498-763x4-324x234", "first_name": "Jhon", "last_name": "Doe", "date_of_birth": "2000-12-01", "email" : "jhon.doe@gmail.com", "phone" : "31641356222", "tags": { "items": [ { "body": "Amsterdam" } ] } } ``` | field name | type | required | description | |------------------|--------|----------|-----------------------------------------------------------------------| | `id` | String | - | - | | `first_name` | String | false | Lists the first name of the customer. | | `last_name` | String | false | Lists the last name of the customer. | | `date_of_birth` | String | false | Lists the date of birth of the customer. Format: `Y-m-d`. | | `email` | String | false | Email address of the customer. | | `phone` | String | false | Phone number of the customer. | | `reference_id` | String | false | Lists the reference\_id of the customer. | | `tags` | Object | false | Lists tags of the customer. | | `segments` | Object | false | Lists the segment the customer is in. | ## Fetching all customers If you want to fetch a collection of customers. ```http copy GET: https://customers.prepr.io/ ``` How to filter the customs is explained on the [Filtering customers](/mutation-api/customers-query-all) page. ## Query by ID Since IDs are unique in Prepr, you can find the customer you want using the id argument. Here is an example that demonstrates how to query an customer with the ID "535c1e-...": ```http copy GET: https://customers.prepr.io/{{uuid}}?fields=custom,email,phone,tags ``` Source: https://docs.prepr.io/mutation-api/customers --- # Filtering the customer list If you want to fetch a collection of customers. ```http copy GET: https://customers.prepr.io/ ``` ## Text search Filter customers by searching in name, company and email fields. ```json copy { "q" : [ { "fz" : "Donald T" } ] } ``` ## Query by email Find a customer by using an email address. ```json copy { "email_eq" : "mail@example.com" } ``` ## Query by reference ID Find a customer by using a Reference ID. ```json copy { "reference_id_eq": "323c93d0-dd2c-40d1-90fb-7454ea06761d" } ``` ## Query by segments Prepr customers can be filtered on segments. You can query the segments field by using the `segments` as an argument. ### Customers that are in the specified segment This example requests all customers in the specified segment. ```json copy { "segments": [ { "eq": "323c93d0-dd2c-40d1-90fb-7454ea06761d" // Segment Id } ] } ``` ### Customers that are in on of the following segments This example requests all customers in one of the specified segments. If a customer is in both segments it will be returned once. ```json copy { "segments": [ { "in" : [ "323c93d0-dd2c-40d1-90fb-7454ea06761d", "8c4b2a7b-9827-4e57-8bd5-1ef04a046238" ] } ] } ``` ## Query by tags If you want to filter customers by related tags. ### Customers that have a specified tag ```json copy { "tags": [ { "eq": "323c93d0-dd2c-40d1-90fb-7454ea06761d" // Tag Id } ] } ``` ### Customers that have one of the following tags ```json copy { "tags": [ { "in" : [ "323c93d0-dd2c-40d1-90fb-7454ea06761d", "8c4b2a7b-9827-4e57-8bd5-1ef04a046238" ] } ] } ``` ### Customers that have all of the following tags ```json copy { "tags": [ { "all" : [ "323c93d0-dd2c-40d1-90fb-7454ea06761d", "8c4b2a7b-9827-4e57-8bd5-1ef04a046238" ] } ] } ``` ### Customers that have none of the following tags ```json copy { "tags": [ { "nin" : [ "323c93d0-dd2c-40d1-90fb-7454ea06761d", "8c4b2a7b-9827-4e57-8bd5-1ef04a046238" ] } ] } ``` ## Expanding fields To request more customer data check out the [Query by ID](/mutation-api/customers#query-by-id) page. ## Sorting customers You can use the `sort` argument to order your query results in a particular order. ```json copy { "sort": "created_on" } ``` It is possible to sort the customers by created, changed, last seen dates in either ascending or descending order. The current values for sorting those fields are `created_on`, `-created_on`, `changed_on`, `-changed_on`, `last_seen`, `-last_seen`. ## Pagination Prepr returns collections of resources in a wrapper object that contains extra information useful for paginating overall results. ```json copy { "skip": 0, "limit": 2 } ``` Will result in: ```json copy { "items": [{...},{...}], "total": 98, "skip": 0, "limit": 2 } ``` In the above example, a client retrieves the next 100 resources by repeating the same request, changing the `skip` query parameter to `100`. You can use the sort parameter when paging through larger result sets to keep the order predictable. For example, `sort=-created_on` will order results by the time the resource was created. ### Limit You can specify the maximum number of resources returned as a limit query parameter. **Note:** The maximum number of resources returned by the API is 1000. The API will throw a Bad Request for values higher than 1000 and values other than an integer. The default number of resources returned by the API is 100. ### Skip You can specify an offset with the skip query parameter. **Note:** The API will throw a Bad Request for values less than 0 or values other than an integer. By combining skip and limit you can paginate through results: `Page 1: skip=0, limit=15 Page 2: skip=15, limit=15 Page 3: skip=30, limit=15 etc.` Source: https://docs.prepr.io/mutation-api/customers-query-all --- # Create, update & destroy customers ## The Customer object ```json copy { "first_name": "Jhon", "last_name": "Doe", "date_of_birth": "2000-12-01", "email": "jhon.doe@gmail.com", "phone": "31612345678", "tags": { "items": [ { "body": "Amsterdam" } ] } } ``` | argument | type | required | description | |------------------|-------------| -------------| ------------| | `id` | String | | | | `first_name` | String | false | Defines the first name of the customer. | | `last_name` | String | false | Defines the last name of the customer. | | `date_of_birth` | String | false | Defines the date of birth of the customer. Format: `Y-m-d`. | | `email` | String | false | Defines email address of the customer. | | `phone` | String | false | Defines phone number of the customer. | | `reference_id ` | String | false | Defines the reference\_id of the customer. | | `tags ` | Object | false | Defines tags of the customer. | ## Create To create a customer. ```http copy POST: https://customers.prepr.io/ ``` Scopes: `customers` `customers_publish` ## Update To update an existing customer. ```http copy PUT: https://customers.prepr.io/{id} ``` Scopes: `customers` `customers_publish` ## Destroy To delete a customer. ```http copy DELETE: https://customers.prepr.io/{id} ``` Scopes: `customers` `customers_delete` Source: https://docs.prepr.io/mutation-api/customers-create-update-and-destroy --- # Signing-up customers Customers represent anonymous and registered people that are engaging with your content. They usually represent website visitors or shop buyers. The Customer API provides methods to get, create, update and delete. ## Creating a new customer You can create a new Customer in your Prepr environment. ```http copy POST: https://customers.prepr.io/ ``` ### Fields | argument | type | required | description | |------------------|-----------| -------------|---------------------------------------------------------------------------| | `first_name` | String | false | Defines the first name of the customer. | | `last_name` | String | false | Defines the last name of the customer. | | `date_of_birth` | String | false | Defines the date of birth of the customer. Format: `Y-m-d`. | | `source` | String | false | Mostly used to define imports etc. | | `email` | String | false | Email addresses of the customer. | | `phone` | String | false | Phone number of the customer. | | `reference_id ` | String | false | Defines the reference\_id of the customer. | | `tags ` | Object | false | Defines tags of the customer. | | `sign_in ` | Boolean | false | Will add a sign in token to the response after creating the new customer. | ```json copy { "first_name": "Jhon", "last_name": "Doe", "date_of_birth": "2000-12-01", "source" : "ios app", "email": "jhon.doe@gmail.com", "phone": "31612345678", "tags": { "items": [ { "body": "Amsterdam" } ] } } ``` Source: https://docs.prepr.io/mutation-api/sign-up-introduction --- # Sign-in with a magic link How to Build Magic Link sign-in. ## Setting-up the email template **Creating a HTML template**\ You can create your own email template to be sent to your customers. First, create an HTML template using your preferred code editor. Then follow the steps below to add it Prepr. **Signing in to your Prepr account**\ Go to [https://signin.prepr.io](https://signin.prepr.io) and sign in with your Prepr account. Then navigate to the Environment you want to create the Sign-In for. **Save the email template**\ Go to **Settings → Email templates** and click **Add template**. Enter a name, and a reply email address like this `Prepr
```
You can enable or disable text alignment in the model and element fields.

***
## Model and element design update
Today we launched a completely new design for managing models and elements. This new design has been implemented to give you an even faster and more enjoyable content modeling experience. Adding or changing fields has become super clear through the use of tabs in the modals.
Let us know about your experience with content modeling in Prepr! [Send us an email to give feedback](mailto:feedback@prepr.io).

***
## Manage the API names of your model
For each content model in your Prepr environment the GraphQL API creates a corresponding GraphQL Type. The Type name is a PascalCase version of the content model name, stripped of all non-alphanumeric characters. Since today's update, you can manage the names of the Singular type and the Plural type. The given display name results in a singular and plural name; both can be overwritten manually.

***
## Overall performance upgrade
*January 6th, 2022*
At Prepr, we find it very important that our application works fast and that all users can quickly perform their tasks in our system. That's why we ended the year with a performance upgrade in which we thoroughly reviewed the code in Prepr CMS. We found out that several code snippets were slowing things down. Therefore, the team optimized specific code snippets for speed. This has improved the performance of the whole system. We hope you've noticed the difference and have optimized your workflow.
***
## Personalize digital content at scale for exceptional customer experiences
*January 3rd, 2022*
We all know by now how important it is to approach your customers in a personal way with targeted content. But how do you do that? Many companies struggle with this because they don't have enough data, content, or know-how. Next month there will be a major beta release of the personalization engine for a select group of customers.
With the updated personalization engine, it will be even easier to deliver hyper-personalized content. We will then introduce Content Targeting which allows you to very easily specify exactly what content should be shown to a particular visitor segment. For example women or men. Or people who have visited a specific section of your website. You can then show them specific banners that are tailored to their preferences and thus improve engagement with your content.

Source: https://docs.prepr.io/stay-updated/changelog2022
---
# Changelog 2021
Find the beautiful features and important updates that were added to Prepr in 2021. This changelog gives you an insight into the most eye-catching releases during this period.
[Latest](#changelog) | [2024](/stay-updated/changelog2024) | [2023](/stay-updated/changelog2023) | [2022](/stay-updated/changelog2022) | **2021**
## Multi-select to copy or delete text fields
*December 2nd, 2021*
Starting today, you can copy or delete multiple text elements at once in the dynamic content field. To select those elements completely, drag your cursor over the elements, or use your arrow keys to do so. Copy the selected elements, paste them elsewhere in the editor, or delete them. [Learn more about the dynamic content field in Prepr](/content-management/managing-content/creating-rich-content#the-dynamic-content-editor).

***
## Publish content on other websites with Embeds Fields
*November 9th, 2021*
The new Embed field allows you to place a content item from Prepr on another website. The embed field is a shortcode in HTML language to copy and paste into your own website.
To add data dynamically from Prepr to your embed code, you can use variables, such as title and id. When adding data to your content item, all variables are replaced in real-time. Using an embed code is simple: just click the ‘Copy code’ button and paste it on your front end. [Learn more about embedding Prepr content on your frontend](/content-modeling/field-types#embed-html-field).

***
## The icon bar is back in the Dynamic Content field
*November 4th, 2021*
After the Dynamic Content field was fully live and we received feedback from our customers, we decided to bring back the icons of the different elements in the Dynamic Content field. As a result, you can now quickly add new elements again at the end of the content. And of course, it is still possible to quickly add an element by pressing the slash key and selecting elements from the dropdown.
By listening to our customers, we want to make the most user-friendly CMS out there. Make sure to send us your feedback if you have any: feedback@prepr.io.

***
## Add static frontend components to your content items
*October 21st, 2021*
Starting today, you can add empty elements to your dynamic content field. This way you can trigger the frontend to insert static frontend components, such as banners, marketing widgets, or forms.
An empty element is an element without fields. All empty elements in a dynamic content field are shown as a label. This way you can easily and quickly recognize the elements.

***
## Add a locale to your content item slug
*September 30th, 2021*
A slug is part of a URL that usually describes the path to the specific content item: it is the part that comes after your domain name in the URL.
Starting today, it is possible to use the content item's locale in the slug construct. This way you can use different slugs for separate locales. [Learn more about working with slugs](/content-modeling/field-types#slug-field).

***
## Publications are now called Content items
*September 28th, 2021*
Today, we changed the name of 'Publications' to 'Content items'. We have done this to avoid confusion: sometimes publications were confused with the model rather than the content item of a model. In addition, we also changed the 'publication link field' to 'content reference field' for the same reason.

***
## Now available for all Prepr users: Dynamic content field for smoothly content editing
*September 27th, 2021*
Today we fully replaced the drag-and-drop editor with an all-new dynamic content editor for all Prepr users. With the new editor, the playground has changed. For this everyday feature, we tried to make it as user-friendly as possible and optimize your workflow. [Please let us know what you think about it!](mailto:feedback@prepr.io)

***
## Make your Tweets interactive by mentioning people
*August 26th, 2021*
With today's update, it is now possible to mention other Twitter users and Twitter accounts in your Tweet publications. Type @ and a part of the name to search for Twitter accounts. This user will be notified immediately after publishing your Tweet.

Please be sure that you have selected the 'Tweet' setting in the publication model text field. Note that this option is only available for Prepr users with the new dynamic content field. [Learn more about sending Tweets with Prepr](/content-modeling/field-types#social-field).
***
## Get notified when something important happens
*August 18th, 2021*
Prepr offers the possibility to be notified of important events in the application. This way you are always aware of events that are relevant to you. Today, we released the notification management tool on the profile page.
To activate personal notifications, enable notifications on your profile page. Select the triggers and choose if you want to receive the notification via email or in the browser.

***
## Major update: dynamic content field for smoothly content editing
*August 16th, 2021*
Today we have an exciting and big update. We fully replaced the drag-and-drop editor with an all-new dynamic content editor. With the new editor, the playground has changed. For this everyday feature, we tried to make it as user-friendly as possible and optimize your workflow.
The editor contains a large white area where you can type and easily decide which elements you want to add. To quickly add a new element in your field, press /, and a pop-up will appear with various elements to choose from. You can quickly add, change, delete, or move elements in the publication field.
It also offers common text formatting options, such as headings, paragraphs, and social embeds, as well as more innovative fields such as publication links and assets with cropping and alignment.

The editor feels direct, like a What You See Is What You Get editor. Headings appear as headings immediately, paragraphs as paragraphs, and social embeds as social embeds. Adding, sorting, and removing elements happen smoothly and fast. [Learn more about modeling the dynamic content field](/content-modeling/field-types#dynamic-content-field).
Starting today, the dynamic content field will be released in phases to all Prepr environments and projects.
***
## Organize your publication with sections, columns, and the small publication view
Prepr offers a unique possibility to properly organize the view of a publication for your editors. By using sections and columns you determine the display of the fields in your publication. This is useful for grouping topics, for example.
**Columns**
Columns are used to properly divide fixed publication fields into one, two, or three columns. This is very user-friendly when you use several smaller fields, such as short text fields, list, color, or boolean fields. With columns, you can display those fields next to each other and organize your publication in a very clear manner.
**Small and wide view**
When you write and manage a lot of texts in Prepr, the readability of those texts can be an issue. Therefore we added the possibility to narrow and widen the view of the entire publication. In longer texts, this is an amazing improvement in readability!
[Learn more about how to organize your publication view with sections and columns](/content-modeling/managing-models#add-columns). Note that this option is only available for Prepr users with the new dynamic content field.

***
## Automize your content workflow (Deprecated)
*August 13th, 2021*
The Prepr automation tool allows you to let Prepr perform tasks for you fully automated. You can set up an automation by selecting a certain task and a certain trigger. For example, you want to delete an article when it's expired. Or let's say you want to create a tweet or a notification when you create a post. This means you don't have to do work twice if you work routinely. This tool will optimize your content workflow in no time.
To create an automation, just click through the three-step wizard. If - Where - Then.

***
## Added support for Luxembourgish locales (lb-LU)
*August 12th,2021*
Luxembourgish locales are now available in Prepr. To set a locale, go to the environment details on the organization settings. You are able to select one or more locales for multi-language publications. This feature is only accessible for owners and users with the 'environments' permission. [Learn more about roles and permissions](/project-setup/managing-roles-and-permissions).

***
## Design update success notifications
*August 11th, 2021*
We recently updated the success and error notifications with a new design. This makes it even clearer what went right or wrong, and what action is expected of you.

***
## App list update: search your apps and filter by status
*August 10th, 2021*
Today we released an update of the app list (formerly known as integrations). With a design update of the app list, we have greatly improved the usability of this page. The app list is now categorized by type of apps, such as Publish, Engage, and eCommerce. You can search for apps and filter apps by status. [Check the user guides for more information about apps](/integrations).

***
## Design update disabled buttons
We appreciate all user input. So, thanks for all your comments! After the latest design update, we received some feedback that users sometimes clicked on disabled-buttons. Those buttons are visible when you (f.e.) reached the maximum number of publications, users, or environments. To increase clarity and usability, we made a design update on disabled buttons today. It is now clearer than ever that you cannot click on these buttons.

***
## Update model settings
*August 4th, 2021*
Today we updated the model settings, making managing model settings easier, clearer, and more user-friendly. When managing a model, your attention is now drawn to the part that is most important. Namely, managing the fields of a model. You can update GraphQL names, validations and review URL's via the button '**Edit settings**'.

***
## Row hover on Prepr tables
*July 28th, 2021*
Today's Prepr update includes an improvement on the data tables in the application. Every table now has a hover state, so you can easily see which row you have selected. This is especially useful in long tables, for example in the list of publications or customers.

***
## Heading styling in the fixed HTLM-editor
From now on you can add heading styling to sections in our HTML-editor. We’ve added this feature to the fixed text fields with appearance set to HTML-editor.
You’ll find the paragraph-heading switch as the first option in the editor:

***
## Get real-time feedback on the strength of your password
*June 25th, 2021*
Your password is very important for the security of your Prepr user account. Today we have therefore added a password indicator so that you can see in real-time whether the password you are using is weak, strong, or very strong.
The password indicator can be found in the onboarding and on the page where you can change your password. [Learn more about account security, two-factor authentication, and single sign-on](/project-setup/managing-users).

***
## Narrow your search results by searching on titles, slugs, or by publication ID
*June 24th, 2021*
To quickly find specific publications in Prepr, you can stack filters and search results in the publication list. We've made it even easier to quickly find publications, now that we offer the option to search by title, slug, or ID. [Learn more about publication search](/content-management/managing-content/managing-content-items#find-your-content-items).

***
## Segment customers based on interaction with specific tags
Segments in Prepr are groups of customers based on one or more common details. You can use segments for engagement analysis purposes, sending notifications, or personalizing your content. Profiles can be grouped based on a variety of personal details, events, and engagement score.
Today, we added an extra feature to our segment builder. You can now group customers who interacted with a publication with one or more specific tags. So if you're looking for all the profiles that have bookmarked the Alaska publication, the segment builder makes those easy to find. [Learn more about our segment builder](/personalization/managing-segments).

***
## Easy reuse of your most used publication filters
*June 15th, 2021*
Speed up your content workflow with saved publication filters! If you often use the same filters in your Prepr environment, you can now save publication filters for quick use in the future. Select one or more filters and save the filter. Now, just click the saved filter to activate.

***
## Added support for Vietnamese locales (vi-VN)
Vietnamese locales are now available in Prepr. To set a locale, go to the environment details on the organization settings. You are able to select one or more locales for multi-language publications. This feature is only accessible for owners and users with the 'environments' permission. [Learn more about roles and permissions](/project-setup/managing-roles-and-permissions).

***
## Copy the API ID of the story on the story page
*June 14th, 2021*
For the developers who use stories to bundle multiple publications, we've added a nice feature today. You can now easily view the story's API ID on the detail page (the list of publications in a story). In the sidebar, you will find the ID under the filters. Click on '**Copy**' to save the ID to your clipboard.

***
## Working with agency user accounts
*June 11th, 2021*
We see that many of our Prepr users have their website or app developed by a web agency. So, today we are releasing a new feature especially for them.
Agency accounts are user accounts of (web) agencies. As of today, these accounts no longer count toward the number of users you can add within your license. So you don't pay for agency accounts. To add an agency user account to your Prepr account, please [contact Prepr Support](https://prepr.io/support).

***
## Manage your model names for GraphQL
*June 10th, 2021*
When you use the GraphQL API to connect your frontend to Prepr, you can now manage the GraphQL singular and plural type name in your publication model. For example, the model name 'News article' generates a type NewsArticle (singular) and a type NewsArticles (plural). [Learn more about Type names for GraphQL in publication models](/graphql-api/fetching-collections).

***
## Click your slug together
*June 9th, 2021*
A slug is part of a URL that usually describes the path to the specific publication: it is the part that comes after your domain name in the URL. You can use slug fields to auto-complete the slug construction.
We've made building a slug construct much easier by allowing you to click on the available slug fields. So no more copy-paste from your API names of the model, but simply click your construct together. [Learn more about working with slugs](/content-modeling/field-types#slug-field)

***
## Publication published? You can see it at a glance
*June 8th, 2021*
In a Prepr content workflow, a publication passes from initiation to publication. Content workflows are very powerful for collaborating on beautiful content for your brand. Prepr content can contain various statuses, such as To do - In progress - Review and Done.
The status alone does not say anything whether a publication has been published. A publication is published if the status is 'Done' and the publication time has expired.
As a result of user input, we are now offering an indication on the publication detail page, with which you can immediately see whether a publication has been published. [Learn more about working with content workflows](/content-management/collaboration).

***
## Duplicate your publications to the current time
*June 7th, 2021*
Prepr contains the powerful possibility to duplicate publications. A small update today ensures that the publishing time of a duplicated publication is not copied over, but is set to the current time. This way you can immediately publish your content at the present moment.
***
## Added support for Lithuanian locales (lt-LT)
*June 1st, 2021*
Lithuanian locales are now available in Prepr. To set a locale, go to the environment details on the organization settings. You are able to select one or more locales for multi-language publications. This feature is only accessible for owners and users with the 'environments' permission. [Learn more about roles and permissions](/project-setup/managing-roles-and-permissions).

***
## Create your publications in a publication link instantly
*May 12th, 2021*
An exciting update to Prepr! Speedy publication linking that dramatically improves how you edit related publications. A publication in Prepr is often related to another publication. For example, an author linked to an article. Previously, it took an average of a whopping 12 clicks to add a new author to an article and change the data. The development team has found a solution for this: publication overlays.
Publication overlays allow you to add and edit related publications directly from the parent publication. So when you write an article, you can directly add an author and change his or her details without leaving the article. You now only need three clicks!
And the great thing is that you can do this endlessly. So no matter how deeply linked your publications are, you can always easily click through and change the data. With publication overlays, managing your content in Prepr has become simpler than ever before. Oh, and you can add roles and permissions to this function as well. For example, you can only allow editors to add a new article and edit existing articles. Boom! You just added a publication in a parent publication four times faster than you used to do.

***
## Manage segments on customers who open your email notifications
*May 5th, 2021*
Prepr keeps track of which of your customers opens and clicks through your e-mails. Since today's Prepr update it is possible to segment this group of customers. This way you can specifically reach this target groups, and also view engagement data from that selection. [Learn more about smart segments](/personalization/managing-segments).

***
## Easily empty your customer lists
*April 29th, 2021*
There are several ways to remove customers from Prepr. You can delete a single customer or delete several at once. Today, we added the possibility to delete all customers in two easy steps.
If you want to remove all customers from your Prepr environment, select the '**Select rows**' option and choose to select all customers. Click the delete button and confirm. [Learn more about managing customers](/personalization/managing-segments#deleting-customer-profiles).
Of course, this is completely according to GDPR regulations. The bulk delete function is only available for roles with the bulk update permission.

***
## Generate links to quickly preview your content
*April 28th, 2021*
Starting today, it is possible to manage one or more review URLs on your publication models. Review URLs are links to your own frontend domains, where you can see what your content will look like after publication. Typical review URLs are links to a production, acceptance, test, and development environment.
Review URLs need to be set once in the publication model. [Find it how you can manage review URLs](/project-setup/setting-up-previews). Nice to know: We regenerated all existing production URLs to the new review URLs.

***
## Design update Prepr tables
Step by step Prepr will be updated with a new, fresh and contemporary design. Today's release adds the new design to the content tables, such as publication lists and customer lists. We also add the new colors to dropdowns, date-time pickers, and autosuggestion input fields.
More to come in the coming weeks, like Prepr in dark mode!
***
## Embed Typeform surveys, questionnaires, and forms to your content
*April 22nd, 2021*
Typeform offers dynamic web forms and online surveys. Starting today, you can easily embed these web forms in your own publications.

To use Typeform, it is important that you have activated a Typeform integration and added the content integration to one of your publication models first. [Learn more about the Typeform integration and form embeds](/integrations/typeform).
***
## Link your publications even more efficiently
*April 13th, 2021*
The publication link is the super-fast way to link from one publication to another. This feature is often used to refer to topics, authors, or as "read more" functionality.
Today's update makes it possible to determine the display of this field in a publication. You can show a link field as a pop-up, or display this field as an autosuggest, and as checkboxes/radio buttons. All three options have their own character:
- **Pop up.** This function, as we already offer it, can be used if you want to search for specific publications. In the pop-up, you can search for publications, filter by assignee or model, and scroll through all search results.
- **Autosuggest.** You can use the autosuggest if you need a specific publication quickly, without having to search extensively. Start typing in your input field and the results will appear immediately.

- **Checkboxes.** This option is best used if you only have a limited set of publications to choose from. An example is a topic or author you want to refer to. When you have indicated a maximum of 1 in your model, the options will be shown as a radio button.

**View publication**
Another trick we added today is the click-through to the publication. From the pop-up, as well as from the autosuggest, or from the checkbox options you can easily click through to the publication you want to link.
***
## Manage asset parameters per publication
*April 8th, 2021*
Do you want to use and describe one asset in different publications? That is now facilitated by Prepr. Today's update makes it possible for you to add a caption to the asset(s) per publication. In this way, you can have the caption in one publication deviate from the caption in the other publication. This is how you can describe the asset very precisely for your specific publication.
Working with multi-language assets
Do you work with publications in multiple languages? Then today's update is very helpful for you. The caption of an asset is language-dependent. This means you can have the caption in one language differ from the description in the other language.
Caption in English publication

Caption in German publication

***
## Align images in text elements
It has also become possible to manage the alignment of assets in a publication. Set where an asset should be displayed between the text elements on your website: choose left, center, or right to determine the position of the image.

***
## Export and import publication elements
*April 2nd, 2021*
In Prepr you can easily export and import publication elements. This prevents a lot of duplication and saves an enormous amount of time. Duplicating or moving publication elements can be very useful in some cases, for example:
- When you also want to use a publication element from one environment in one of your other environments.
- Or if you want to turn publication elements into shared content elements.

Learn more about [exporting and importing publication elements](/content-modeling/managing-components#export-and-import-a-component) or read our Prepr blog post about [Shared content models and elements](https://prepr.io/blog/minimize-errors-and-maximize-development-speed-with-shared-content-models).
***
## Sending Tweets with Prepr
*March 30th, 2021*
Writing and sending Tweets via Prepr is as easy as publishing a website article or web page. [Let us show how you can easily publish](/content-modeling/field-types#social-field) to this world-class social media platform. You can enter the Tweet text, and enrich the Tweet with photos, a video, and a link to another Prepr-publication. Multi-channel publishing, all from one platform.

**Note:** You need to link a Twitter account once and set up the publication model correctly. [Learn more about how to set up your Twitter integration](/content-modeling/field-types#social-field).
***
## New indigo color in Prepr application
*March 29th, 2021*
Step by step Prepr will be updated with a new, fresh and contemporary design. Today's release adds the new design to the Prepr menu bar. The action buttons (such as 'Add publication') are also provided with the new indigo corporate identity. More to come in the coming weeks, like Prepr in dark mode!

***
## Export customers with special export permission
*March 23rd, 2021*
Prepr has carried out an important update in GDPR compliance. As of today, Prepr users can only export customer lists if they have the special 'export' permission.
To add the permission to a role, go to **User management** → **Roles** in the organization settings and select a role. Select the option 'Allow user to export customers' to give users with this role access to the export function.

**Note:** All current Admin roles with the 'customers' permission have been given this export function.
***
## Auto-complete your publication slugs with parent publications
*March 22nd, 2021*
A slug is part of a URL that usually describes the path to the specific publication: it is the part that comes after your domain name in the URL. You can use different slug variables to auto-complete the slug construction, such as `id` and `title`.
From today, Prepr also offers the possibility to include linked parent publications in your slug construct. This is a huge asset for Prepr users who point through publication links to other publications in their Prepr account. [Learn more about working with publication slugs](/content-modeling/field-types#slug-field).

***
## Start using asset metadata (Exif)
*March 17th, 2021*
For many Prepr users, the default asset titles are not sufficient, as many file names are indefinable. That's why Prepr offers the Exif integration to automatically add metadata (Exif) of the photo, video, audio, or document. Go to **Integrations** → **General** → **Exif Integration** to specify which Exif-data of the asset you want to use. You can choose to replace the title, description and/or author. [Learn more about asset metadata](/integrations/image-processing/exif).

***
## A/B-test winner selection
*March 16th, 2021*
Prepr A/B tests give you the power to perform A/B tests with your content in an easy-to-implement way. By A/B-testing your content frequently, you increase CTR and time spent. Zoom in on retrieved metrics and learn what content works best – or improve the content that needs tweaking.
Since today's update, it is possible to choose the version you want to continue with. This is typically the version with the best CTR, the winner. Switch off the A/B test option and choose your winner. [Learn more about A/B-testing](/ab-testing/running-ab-tests).

***
## Handling events from Mailgun
*March 11th, 2021*
The Mailgun integration in Prepr enables you to send email notifications and sign-in invitations with your own email domain settings. Today's update also makes it possible to register who views and clicks your emails: the events are stores in Prepr now. It is therefore important to select the right region and enter the Mailgun signing key.
When someone opens their email, Prepr registers an 'open' event, and with a click-through in the email, we record a 'click'. You can find detailed insights into the engagement score in the Analyze section.

***
## Sort asset field in a publication element
A small update today on the asset field in Prepr. We have now made it possible to sort assets in a publication element asset field. Drag and drop the assets in the order you wish. This update aligns the operation of the asset field with the asset field in a publication model and the asset field in a drag-and-drop editor.

***
## Update Prepr menu and application URLs
*March 10th, 2022*
Last night a major update went live in the Prepr application.
**Changed menu items**
Prepr takes care of the entire workflow of publishing content, engaging customers, and analyzing data. For that reason, the terminology in the Prepr application has been aligned. The most eye-catching changes:
- Content has been updated to Publish
- Audience is converted to Engage
- People and profiles are now called Customers
- Interactions are named Events now
Most of our users will only see a small number of menu items, as their Prepr access has been defined with a custom user role. To increase the user-friendliness of Prepr, the menu items have been written out completely, so you can surf and find your content even faster!

**Updated URL structure**
Due to speed improvements and a better, consistent user experience, the URL structure of the Prepr application has been changed. The URL structure is now built in the same consistent manner throughout the application. As a result, some application URLs may be broken.
**Note:** This change may mean that users with browser bookmarks have to change their favorites.
***
## Filter on publication link fields
*March 9th, 2021*
A new filter on the publication list has been added today. In the current situation, there are publication filters on the publication status, assignee, publish time, and tags. You can stack filters and search queries in order to narrow your search results effectively.
Today's update enables you to specify the filter on publication model. When there is a 'Publication link' model field in the selected model, an extra filter shows up in the publication list. This filter shows all publications that are linked to in this model.

**Example: "Filter all articles by author Gérard Vue"**
You have created an 'Article' model with a publication link field to the 'Author' model. By selecting the model filter with 'Article' a new filter on 'Author' is made visible, containing all publications of the 'Author' model.
So now you are able to filter all publications with the 'Article' model, where the author is set on a specific author.
***
## Nofollow tags in publication editor
*March 8th, 2021*
Today's update contains an improvement in Search Engine Optimization. It is now possible to add nofollow HTML tags to links in the text editor.
Nofollow links are links with a rel=”nofollow” HTML tag applied to them. The nofollow tag tells search engines to ignore that link. Because nofollow links do not pass PageRank they likely don’t impact search engine rankings.

***
## Filter on publication model in webhook trigger
*March 4th, 2021*
When you have selected a publication event, you will receive notifications when a publication is created, (un)published, changed, or deleted. You can further specify which publications you want to receive notifications from. Select one or more publication models to receive webhook events for publications of that specific model. Selecting none will act as a wildcard. [Learn more about webhooks](/development/best-practices/webhooks).

***
## Select all days in schedule
*March 3rd, 2021*
A small update today improves the usability in the Prepr schedules. When you want to schedule a program on all days of the week, you can now click on 'Days'. All days of the week are then selected. As simple as that!

***
## Publication elements as predefined publication fields
*February 22nd, 2021*

Custom publication elements have been available for a long time in Prepr as a way to define your elements in the drag-and-drop editor. And now, these custom elements can also be used as a standard field in a content model. This allows you to define your content models even better, gives you more control over validation, and lets you retrieve data in a more structured way through the API.

***
## Seamless eCommerce integrations
*February 17th, 2021*
We are proud to announce our new integrations for the headless commerce tools: CommerceTools and Commerce Layer. With two clicks you are now able to refer to the products on your website in an article. This integration helps you to work faster and get all the data that you need from one database. [Learn more on how to add e-commerce content integrations to Prepr publications](/integrations).

***
## Update publication scheduler
*10 February 19th, 2021*
We find an optimal and intuitive user experience very important. That's why we updated the publication scheduler, which was closed by default in the publication sidebar. The update ensures that the scheduler remains open when a publication date in the future has been entered, or an archive date has been added.

3 February
***
## A/B-test your way into success
*February 3rd, 2021*
Prepr A/B tests give you the power to perform A/B tests with your content in an easy to implement way. By A/B-testing your content frequently, you increase CTR and time spent. Zoom in on retrieved metrics and learn what content works best – or improve the content that needs tweaking.

- Implementation of A/B-testing needs a configuration of your website or app as well. [Learn more on how to implement A/B-testing on your app or website](/ab-testing/setting-up-ab-testing).
- Once your website or app is optimized for A/B-testing, you can start A/B-testing in a single click. [Learn more about the A/B-test functionality in Prepr](/ab-testing/setting-up-ab-testing).
An A/B test is a randomized experiment using two variants of the same publication (A and B). Variant A is the original and variant B through n each contain at least one element that is modified from the original. Before you can start testing, you need to create at least one B version of a publication.
**Note:** A/B-testing is under a Limited Availability Program. Contact support@prepr.io for more information on how to join the program.
***
## Send email notification to prize winners
*February 2nd, 2021*
The Prepr Contest Module is a powerful and secure solution to manage prizes, contests, and winners. In addition to the ability to automatically send winners an email notification, we have now added the option to send notifications to winners that have been added manually. To send an email notification, simply select the checkbox on the prize detail page. Learn more about Prepr Contests.

1 February
***
## Removed requirement if the status is not 'DONE'
*February 1st, 2021*
This update allows you to save a Prepr publication when the status of this publication is not set to DONE. This way you can save drafts or pending publications without entering the required fields.
***
## Replace old editor with Froala editor in timeline edit modal
*January 29th, 2021*
Some users experienced problems saving talks in their timeline. This update ensures that only one editor type is loaded when a timeline opens. This results in a significant improvement in the loading speed. Talks are therefore processed faster so that they are all saved correctly.
***
## Added support for Namibian locales (en-NA)
*January 28th, 2021*
Namibian locales are now available in Prepr. To set a locale, go to the environment details on the organization settings. You are able to select one or more locales for multi-language publications. This feature is only accessible for owners and users with the 'environments' permission. [Learn more about roles and permissions](/project-setup/managing-roles-and-permissions).

***
## Fix list item field in elements for accepting comma
Users experienced a bug when list options were added together, in case one of the list options contained a comma. A bug fix makes it possible to add list options with a comma again.

***
## Show and export multiple track break notes
*January 27th, 2021*
This update of Prepr for Radio allows you to display multiple columns of your playlist export in the Prepr timeline.

***
## New icons in publication elements
*January 26th, 2022*
This update also includes an update Font Awesome to the latest icons (version 5.15.2)
***
## Preview step in media browser
*January 22, 2022*
When you upload or select media in the media browser, it is now possible to view all selected assets. Click on 'Show selection' to see a preview of the media items. In this screen, you can confirm the assets, or make adjustments to the selection (such as removing an asset).

***
## Resource element show invalid URL only when type Webpage selected
*January 20th, 2021*
An error notification was visible when an invalid URL was entered and type was set to 'Audio' or 'Other'. We added extra validation for the resource element in a drag-and-drop editor: only webpage URLs are validated now.

***
## Add \*.svg to accept upload on select type "file" in field
We added support for SVG-files in the Prepr uploader in publications.
***
## Import profiles with CSV-import
*January 19th, 2021*
Prepr provides a solution for the manual import of profiles. This import takes place on the basis of predefined column titles in a CSV file. Check the user guides.

***
## Publication status in publication link
A little update on the publication link field contains the visibility of the publication's status. You can easily check if the linked publication has the DONE status, or whether the publication needs to be completed.

***
## Add segment rules for ‘has full name’ yes/no
*January 14th, 2021*

***
## Notification when the schedule is not conclusive
For optimal operation of the On Air functionality in Prepr, it is important to fill in the program guides and clock guides completely. We added a yellow notification bar in the guide when there are gaps in the schedule.

***
## Update search Prepr for Radio
*January 13th, 2021*
The search function has changed substantially. Here are some of the highlights:
- Update default search time range for speed improvements
- Update publication type filtering (removed unused publication types)
- We've added a click-through to the Tracks, TrackPlays and Memos
***
## Person webhook events added
*January 11th, 2021*
Webhooks allows your app to easily receive notifications whenever there are updates to a chosen set of events. Webhooks are often used for deploying a static website when content is changed or syncing data to an external search engine platform. We added person webhook events in the Prepr application, so you can subscribe to be notified whenever a new person (customer) is created, changed, or deleted. [Learn more about webhooks and webhook events](/development/best-practices/webhooks).

***
## Preview notification email in publication
*January 7th, 2021*
When you have added a notification field to a publication and selected an e-mail template, you can now view the example email notification via the 'preview' button.
***
## Move ‘Import model’ to ‘Add model' dropdown
To create a cleaner view in the publication model list, we moved the 'import model' button to the Add model dropdown.
***
## Various updates
*January 6th, 2021*
***
## # Add winner on prize detail
It is now even easier to add winners to the Prepr database. Simply click on 'Add winner' on any prize detail page to add one or more winners.

***
## # Add vote interaction on the profile page
Apps and websites can submit different event types via our pixel. We added support for event type 'Vote', which means that votes on publications are visible in Prepr. We also made the 'vote' type visible on a profile detail. [Check the various event types on our developers portal](/data-collection).

***
## # Add email template from template
Building an email template from scratch can be challenging. That is why we have added a default email template for notifications, so you can easily start sending email notifications.

***
## # Add publication model from a template
Do you want to get started quickly with publication models? We added some default models, such as 'blog post' and 'page', so you won't need to get modeling yourself. [Learn more about publication models](/content-modeling/managing-models).

***
## # Fix content integration item in publication element
Bugfix for custom data in a content integration, used in a publication element in a drag-and-drop editor.
***
## Added support for multiple Publication Models in the Publication Link field
*January 4th, 2021*
Users noted that in a publication model field and in a publication element field, they can only use publication links to publications from one or all models. Thanks for this input! We have now added support for links to all, one or more models. [Learn more about publication links](/content-modeling/field-types#content-reference-field).

***
## Deprecated features
- Notifications
Source: https://docs.prepr.io/stay-updated/changelog2021
---
# Stay updated
We aim for full transparency and are always here to help out. Explore our newest features and [learn about improvements we're working on](/roadmap).
Source: https://docs.prepr.io/stay-updated
---
# Shared schema
*This article explains how you can create and use a shared schema in Prepr to keep the structure of your content consistent across multiple environments in an organization.*
## Use cases
The *Shared schema* feature lets organizations use the same structure for content across different brands.
While each brand might need unique content, it's smart to use the same overall structure for all brands.
In this case, create a shared schema to use the same schema across multiple environments with a shared schema.
Another use case is managing deployments across your development, testing, acceptance and production environments.
You can create entities in your non-production environment, test them, and then promote these to a shared schema when they're ready for production.
The shared schema can then be used across the whole DTAP setup.
In all use cases, the shared schema makes development faster and easier by keeping the code base leaner and more consistent.
## Create a shared schema
To create a *Shared schema*, follow the steps below.
1. Click the environment dropdown at the top right, choose your organization and click to open the environments overview.
2. Click the **Shared schema** tab to open the shared schema page.

3. Add models, components, enumerations and remote sources to complete your schema.
Check out the [Create schema docs](/content-modeling) for more details.
When completed, each of the entities in the shared schema can be used in any environment in your organization.
## Promote entities to the shared schema
You can directly promote any model, component, enumeration, or remote source from an environment to the *Shared schema* at the organization level.
Once promoted, these entities can be accessed in any environment within the same organization.
To promote a schema entity to the shared schema, follow the steps below.
1. Go to the environment for the schema entity that you want to promote and click the *Schema* page.
2. Click the model, component, enumeration or the remote source that you want to promote to open it.

3. At the top of the detailed page of the entity, click the icon and choose the **Promote to shared schema** option.
4. If the entity has no linked entities that are not yet in the shared schema, your entity will become shared.

If you don't have the *Promote to shared schema* feature enabled, [contact our Sales team](https://prepr.io/contact-sales) for more details.
## Choose field visibility for environments
You can control field visibility per environment when using a shared schema, ideal for multi-site or multi-brand setups where fields differ slightly between environments.
To choose which environments a field can be visible for editing, follow the steps below.
1. In your shared schema, go to the relevant model or component and simply click the field to open the field settings.
2. Open the **Appearance** tab and go to the *Conditional visibility* section.

3. Select the **Show field based on environment name** option and choose all the environments where this field needs to be visible.
4. Click the **Save** button to save the settings.
Now, editors will only see this field if they're working in one of the environments you've chosen in the setting above.
Source: https://docs.prepr.io/project-setup/architecture-scenarios/shared-schema
---
# Shared content
The shared content feature supports multiple brands in an organization.
Sometimes, different brands want to share content within the same organization.
For example, each brand creates their own articles, but these articles belong to common categories.
This can be done with shared content.
To enable sharing of specific content, follow the steps below.
1. Go to the **Shared schema** tab in your organization.
2. Open the content item with the relevant content reference for the content you want to share.
3. Click the existing content reference field or create a new [content reference field](/content-modeling/field-types#content-reference-field) to a model.
and in the *General* tab, enable the toggle **Allow items from all environments**.

Check out the [Create schema docs](/content-modeling) for more details.
Source: https://docs.prepr.io/project-setup/architecture-scenarios/shared-content
---
# Architecture scenarios
Discover advanced Prepr CMS features tailored for more complex project structures and organizations.
Source: https://docs.prepr.io/project-setup/architecture-scenarios
---
# Blog
*This guide shows you how to model a typical blog, one of the most common patterns when implementing a web app.
Check out our [demo blog](https://acme-lease.prepr.io//blog) in action.*
## Introduction
A typical blog is made up of two key web pages, an overview page and a detailed page for each blog post.
### Overview page
In the example below, you can see the overview page includes a list of blog posts with some key content.
In this example, the list includes the post title, a cover image and an excerpt of the post.
This page also includes a list of categories that you can click to filter the posts to view similar posts.
The link in each post allows the visitor to navigate to the detailed blog post page.

### Detailed blog post
In the example below, you can see more detail about a specific post, including the main content body of the post, and author information.

You can use these sample web pages as a basis when modeling the content you need in your web app.
Start by visualizing the *Post* model first.
## Post model
When modeling your content for the blog, you can start with the main model for each post, the *Post* model.
Check out the fields you can add to the *Post* model:

|Field name |Field type | Description|
|------------------|-------------|--------|
|**Title**| [Text](/content-modeling/field-types#text-field) |The title of a post visible on the web app. Required. This title can be used to query the post through the API. |\
|**Slug** | [Slug](/content-modeling/field-types#slug-field) |Part of the URL that is used to link to the detailed post page. Required. The slug is also useful as an internal field for API queries on this post. We set it to the *Title* of the post.|
|**Cover** | [Asset](/content-modeling/field-types#asset-field) |The cover image for the post. Required. Configure presets to cater for different dimensions in the web app, for example: to display the main cover in the detailed page and when displaying the image in a card.|
|**Categories**| [Content reference](/content-modeling/field-types#content-reference-field)|A reference to the [*Category*](#category) model. The category field allows the post to be grouped which can be used in the web app in different ways, for example, to filter posts by a category.|\
|**Author**| [Content reference](/content-modeling/field-types#content-reference-field)|Used to reference the [*Author*](#author) model which has content about the people who create the posts.|
|**Content**| [Dynamic content](/content-modeling/field-types#dynamic-content-field)| This field is the main body of the post and we define it to allow the content editor to include the following elements: - Heading2, Heading3, and Heading 4 - Paragraph: Allow bold, italic, and ordered list styles as well as links within the post.- Assets: For images and videos.|
|**SEO**|[Component](/content-modeling/field-types#component-field)|An embedded SEO component. This component has fields for finding this post through search engines. |
See a complete list of all other available [Prepr field types](/content-modeling/field-types).
You'll notice that some of the fields in the *Post* model are content references (link to items from another model) and components.
You can define those referenced models and components as follows:
### Author model
You can set up an *Author* field in the *Post* model. This field is a *Content reference* to a separate *Author* model.
*Author* is set up as a model to avoid duplication of person content. Check out the fields you can define in this model.
{/* The idea is that there could be content for persons with other functions and not only for article authors. For example, imagine that employees are shown in an *About us* page. The general *Person* model caters for this use case too and makes your schema more flexible and robust. */}

|Field name |Field type | Description|
|------------------|-------------|--------|
|**Name**| [Text](/content-modeling/field-types#text-field) |The name of a person. Required.|
|**Image**|[Assets](/content-modeling/field-types#assets-field)|The asset field allows the content editor to add a photo of the person to the *Author* content item.|
### Category model
You can define a *Categories* field in the *Post* model. This field is a *Content reference* to a separate *Category* model. This makes the category content reusable in the web app. For example, different posts can have the same categories.
Check out the fields you can add to the *Category* model.

|Field name |Field type | Description|
|------------------|-------------|--------|
|**Name**| [Text](/content-modeling/field-types#text-field) |The name of a category visible on the web app. Required. This name can be used to query the category through the API. |\
|**Slug** | [Slug](/content-modeling/field-types#slug-field) |Part of the URL that is used to link to this category. Required. The slug is also useful as an internal field for API queries on this category. We set it to the `{name}` of the category.|
### SEO component
You can set up the *SEO* field in the *Post* model. This field is an embedded *Component*. SEO is set up as a component because its field structure can be reused used in multiple content items from different models, namely, the *Post*, and *Page* models.

Within the *SEO* component we define the following fields:
|Field name |Field type | Description|
|------------------|-------------|--------|
|**Meta title**|[Text](/content-modeling/field-types#text-field)|The title tag. This title is the criterion for search engines to find a web page, for example. It is also the title that appears when an item is shared on social media. |
|**Meta description**| [Text](/content-modeling/field-types#text-field) | A brief description about a particular content item, for example, this description can be included in a summary view of a post in your front-end. This is also the description used when this item is shared on social media.|
|**Meta image**| [Assets](/content-modeling/field-types#assets-field) | This image is used when displaying a link to this item, for example, the Open Graph image that you see when sharing links within social media. |
## Other use cases
In conclusion, this is just one example of how you can model a blog pattern for your web app. Feel free to reuse this structure and amend it to your needs.
You could also consider including the following use cases in your schema.
- Add the author's social media info. You could set up social media info as a component and embed it in the *Author* model.
- Create a more generic *Person* model with a field for role information. If you need to show some employee information in your front-end, it's a good idea to allow their roles to be stored for this purpose.
## Want to learn more?
Check out the following guides:
- [More example patterns](/content-modeling/examples)
- [How to create a model in Prepr](/content-modeling/managing-models)
- [How to create a component in Prepr](/content-modeling/managing-components)
Source: https://docs.prepr.io/content-modeling/examples/blog
---
# Page
*A page is one of the basic parts of a web app.
Check out our [demo home page](https://acme-lease.prepr.io/) in action.*
## Introduction
This guide takes you through the content modeling process for a page pattern and explains the reasoning behind the modeling decisions. We'll look at how to model a feature-rich web page with a variety of elements. Here is a sample web page we used as a basis for the modeling:

Let's take a closer look at the modeling steps. Using this page as a basis, we see that a number of elements make up the page content. These include:
- **A hero section**
The hero section is the prominent part of the page usually at the top. It has a heading, a sub-heading, an image, and one or more buttons.
- **A feature section**
The feature section showcases important features to highlight and consists of a heading, a sub-heading, button, image and the image position.
- **CTA**
A call-to-action to encourage interaction from the web visitor.
- **Static**
Some static sections to showcase more static info like testimonials.
- **Cards**
Cards are used for things like a selection of blog posts or recommended products. It has a heading, sub-heading, a stack of cards for the items like posts or products.
- **FAQ section**
A FAQ section to show some common questions and the corresponding answers.
- **Contact section**
This section gives visitors the opportunity to contact the company.
Let's look at how to structure a page like this in more detail.
## Page model
In our schema, we've decided to create a generic *Page* model that can be used for different kinds of web pages, for example, a home page, marketing pages, landing pages, etc.
See an example *Page* model below:

Within the *Page* model we define the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Title**| [Text](/content-modeling/field-types#text-field) |The title of the page. Required. This title is used internally to identify the page in Prepr.|
|**Slug**| [Slug](/content-modeling/field-types#slug-field) |Part of the URL that is used to link to this page. The slug can also be used for API queries to request this page and is automatically set to the title of the page in our example.|
|**Content**| [Stack](/content-modeling/field-types#stack-field)| The main content of the page. Using the Stack field allows editors to add the elements that make up the web page easily, for example, the hero section, a CTA, FAQ section, etc. |
|**SEO**| [Component](/content-modeling/field-types#component-field)| SEO is an embedded component which contains fields that are used by search engines and social media. We reuse the same SEO component defined in the [Blog pattern](/content-modeling/examples/blog) doc.|
See a complete list of all other available [Prepr field types](/content-modeling/field-types).
## How to model the elements on a page
In our example model above we put the main page content in a *Stack* field.
The *Stack* field allows content editors to easily create all the elements they need on a page.
They can add both components and content items to the stack.
The *Stack* field contains the following components and models in our *Page* model:
|Model/component |Type| Description|
|------------------|-------------|--------|
|**Hero**| Component|The hero component at the top of the page. |\
|**Feature**| Component| The feature component to allow editors to capture a heading, a sub-heading, button, image and the image position (left or right).|
|**CTA**| Component| The component for a call-to-action.|
|**Cards** | Component|The component to show recommendations or posts as cards. The editor can link existing *Product* or *Post* content items. Check out the [*Blog pattern*](/content-modeling/examples/blog#article-model) doc for more details.|
|**FAQ** | Model|A reference to existing reusable question and answer content. |
|**Contact**| Component| A component to allow editors to include a contact form in the page.|
Let's look at each element in detail.
### Hero
The *Hero* component is used to include the most prominent part of the page usually at the top.

The *Hero* component has the following typical fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Heading**| [Text](/content-modeling/field-types#text-field) |The heading usually at the top of the Hero section.|
|**Sub Heading**| [Text](/content-modeling/field-types#text-field) |More descriptive text just below the heading.|
|**Image**|[Assets](/content-modeling/field-types#assets-field)|An asset field that allows editors to include an image in the *Hero* section.|
|**Buttons**| [Stack](/content-modeling/field-types#stack-field) |One or more buttons with their respective fields.|
### Feature
The *Feature* component in a page can be used to highlight important features.

The *Feature* component typically has the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Heading**| [Text](/content-modeling/field-types#text-field) |The title of the *Image and text* block.|
|**Sub heading**| [Text](/content-modeling/field-types#text-field) |The text content.|
|**Button**|[Component](/content-modeling/field-types#component-field)|This component allows editors to label the button and to either link the button to a URL, another page in the website, or to another content item. Maximum of one button or link.|
|**Image**|[Assets](/content-modeling/field-types#assets-field)|An asset field that allows the editor to attach an image. Maximum of one asset with `image` asset type.|
|**Image position**| [List](/content-modeling/field-types#list-field)| The position of the image in relation to the text, for example, image to the left of the text or to the right of the text.|
### CTA
The *CTA* component can be used to encourage interaction from the web visitor.

The *Call to action* component typically has at least the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Heading**| [Text](/content-modeling/field-types#text-field) |The heading text for this call to action.|
|**Sub Heading**| [Text](/content-modeling/field-types#text-field) |More descriptive text for this call to action.|
### Static
The *Static* component can be used to showcase more static info such as testimonials.

The *Static* component can be made up of at least the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Title**| [Text](/content-modeling/field-types#text-field) |The title for this section.|
|**Static Type**| [List](/content-modeling/field-types#text-field) |Based on this value, the front end can determine how to display the static content, for example, testimonials or steps.|
### Cards
The *Cards* component can be used to show highlighted blog posts or recommended products.

The *Cards* component is typically made up of the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Heading**| [Text](/content-modeling/field-types#text-field) |The heading text for the collection of cards.|
|**Sub heading**| [Text](/content-modeling/field-types#text-field) |More description text just below the heading.|
|**Cards**| [Stack](/content-modeling/field-types#stack-field) |Used to include several posts or product content items.|
|**Button**| [Component](/content-modeling/field-types#component-field) |This component allows editors to label the button and to either link the button to a URL, another page in the website, or to another content item. Maximum of one button or link.|
### FAQ
The *FAQ* model is useful to include some common questions and the corresponding answers.
By creating a model instead of a component, the content is reusable and the same questions and answers can be referenced in multiple pages.

The *FAQ* model is made up of the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Internal Title**| [Text](/content-modeling/field-types#text-field) |The front end uses this field to link to the correct FAQ content item.|
|**Title**| [Text](/content-modeling/field-types#text-field) |The title for the section in the page.|
|**Questions**| [Stack](/content-modeling/field-types#text-field) |A list of questions and their corresponding answers.|
### Contact
The *Contact* component can be used to give website visitors the opportunity to contact the company.

The *Contact* component is typically made up of the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Heading**| [Text](/content-modeling/field-types#text-field) |The heading text for this contact form.|
|**Sub heading**| [Text](/content-modeling/field-types#text-field) |More descriptive text just below the heading.|
|**Form title**| [Text](/content-modeling/field-types#text-field) |The contact form title.|
|**Phone number**| [Text](/content-modeling/field-types#text-field) |Used for your company telephone number.|
|**Email**| [Text](/content-modeling/field-types#text-field) |Used to show the company email address.|
|**hubspot\_form\_id**| [Text](/content-modeling/field-types#text-field) |If you [add the HubSpot integration](/integrations/hubspot), you can use a matching `hubspot_form_id` to link to an existing HubSpot contact form.|
|**hubspot\_portal\_id**| [Text](/content-modeling/field-types#text-field) |If you [add the HubSpot integration](/integrations/hubspot), you can use a matching `hubspot_portal_id` to link to an existing HubSpot contact form.|
## What's next?
Now that you know how to model a page, let's go a step further and look at [how to set up personalization](/personalization/setting-up-personalization) doc.
## Other use cases
This guide explains how you can design just one example of a page for your web app. This page can be used for several types of pages, for example: home page or landing pages.
Feel free to use this structure and amend it to your needs.
Another use case we haven't covered could be a **Job postings** page.
In some cases, you may have to access content that is maintained in another system, for example, job postings information.
It makes sense that you may want to retrieve the items from the other system to ensure you have up to date information in Prepr.
In this example, you can include a job postings element on your page that references the job postings from the external system.
Prepr allows you to set up remote content in your model or component which is retrieved from a custom source.
Check out [how to set up a custom remote source](/content-modeling/creating-a-custom-remote-source) doc for more details.
## Want to learn more?
Check out the following guides:
- [More examples](/content-modeling/examples)
- [How to create a model in Prepr](/content-modeling/managing-models)
- [How to create a component in Prepr](/content-modeling/managing-components)
Source: https://docs.prepr.io/content-modeling/examples/page
---
# Navigation
*Navigation is a key structure that is implemented in every web app. In this article, we look at a typical navigation structure and explain the reasoning behind the modeling decisions.*
## Introduction
First, let's look at an example of a top navigation. This structure is the basis for our modeling process:

Using this example as a basis, we see that this navigation has a number of top-level (parent) menu items and these parent menu items have a number of child menu items. Prepr supports this type of nested items with the standard *content reference* field. It's possible for you to create content that references other content, even of the same *Model*. Check out the [Content reference field](/content-modeling/field-types#content-reference-field) docs for more details.
When a user clicks the lowest level child menu item, they are directed to a different page.
Let's look at the *Navigation* model in more detail.
## The navigation model
The *Navigation* model is a simple model, but is our starting point for this pattern.
See an example *Navigation* model below:

Within the *Navigation* model we define the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Title**|[Text](/content-modeling/field-types#text-field)|The title of the navigation, for example, *Top navigation*. Required. This title can be used to query the navigation through the API. |
|**Menu items**| [Content reference](/content-modeling/field-types#content-reference-field)|The navigation almost always has several menu items. This field makes a reference to the *Menu item* model. |
See a complete list of all other available [Prepr field types](/content-modeling/field-types).
Now, let's look at the *Menu items* field in more detail.
### Menu items
We set up a *Menu items* field in the *Navigation* model. This field references a *Menu item* model to avoid duplication of menu item content. The idea is that there could be content for the same menu items in different locations throughout the web app. For example, imagine that the same menu item appears in the top navigation as well as in the footer of a web page. This generic *Menu item* model caters for this situation and makes your schema more flexible and robust.

Within the *Menu item* model we define the following fields:
|Field name |Field type| Description|
|------------------|-------------|--------|
|**Title**|[Text](/content-modeling/field-types#text-field)|The title of the menu item visible on the navigation, for example, *Events*. Required. This title can also be used to query the menu item through the API. |
|**Link to page**| [Content reference](/content-modeling/field-types#content-reference-field) |When a user clicks a menu item, this field is used to open the correct internal page linked to this menu item. For more details on the Page model, check out the [Page pattern](/content-modeling/examples/page).|
|**Link to external page**| [Text](/content-modeling/field-types#text-field) |When a user clicks a menu item, this field is used to open an external page linked to this menu item. In Prepr, you can set this text field as HTML and enable the *Link* option.|
|**Description**|[Text](/content-modeling/field-types#text-field)| A short description for the menu item that is visible on the navigation, for example, *Check out our upcoming events*. |
|**Icon**|[Assets](/content-modeling/field-types#assets-field)|An optional icon that represents the menu item.|
|**Children**| [Content reference](/content-modeling/field-types#content-reference-field)|A reference to the *Menu item* model itself to create a parent-child hierarchy. The front-end queries this field to find all the children menu items for a particular parent.|
## Other use cases
In conclusion, this is just one example of how you can model any navigation for your web app. Feel free to use this structure and amend it to your needs.
- If you'd like to specify the display order of your children menu items in the content, consider adding a number field to the menu item model to specify the order. In this way, the front-end doesn't have to be updated when menu items need to be re-ordered.
## Want to learn more?
Check out the following guides:
- [More example patterns](/content-modeling/examples)
- [How to create a model in Prepr](/content-modeling/managing-models)
Source: https://docs.prepr.io/content-modeling/examples/navigation
---
# App config
*Application configuration is static information about a web app that seldom changes. In this article we look at an example of a typical application configuration model.*
{/*
You can create this pattern in Prepr automatically when you create a model. Choose the *App config pattern* template and the model described below will be created for you. */}
## Introducing the single-item-model
A lot of application configuration is not actually visible on a web app, but is essential to creating a working web app. Prepr supports this type of static once-off setup with the *single-item model*. The *single-item model* makes it much simpler for developers to query this type of content. Check out the [Single-item model](/content-modeling/managing-models#single-item-model) docs for more details.
Examples of app config content include, but is not limited to:
- *App name* - This is the name of the web app that is visible, for example when the app appears in a search list.
- *App description* - This is the brief description that is visible, for example when the app appears in a search list.
- *Company contact info* - This is information like the company's address and telephone number that is displayed on a web site.
- *Meta tags* - These are searchable tags at a web app level rather than at a page level.
- *Copyright information* - This is the static text that one often sees at the bottom of a web app to indicate copyright information.
Let's look at an *App config* model.
## An App config model
We define *App config* as a single-item model. This means that a content editor can only create one App config item. A single item also makes it easier for the front-end to query this content.
See an example *App config* model below:

Within the *App config* model we define the following fields:
|Field name |Field type | Description|
|------------------|-------------|--------|
|**App name**|[Text](/content-modeling/field-types#text-field)|The app name is listed in internet searches or in the case of a mobile app is the name search in an app store. |
|**App description**| [Text](/content-modeling/field-types#text-field) | A brief description which is shown together with the *App name* in internet searches.|
|**Company contact info**| [Text](/content-modeling/field-types#text-field) | The company's address and telephone number. This content can then be displayed in the web app.|
|**Meta tags**| [Tags](/content-modeling/field-types#tags-field) | General tags for search engines to find the web app. These tags are not specific to particular pages.|
|**Copyright info**| [Text](/content-modeling/field-types#text-field) | The static text for copyright information on the web app.|
See a complete list of all other available [Prepr field types](/content-modeling/field-types).
## Other use cases
In conclusion, this is just one example of how you can structure app config. Feel free to use this structure and amend it to your needs.
- If you would like to include a *Follow us* box in your web app, you could also design a *Social media links* field that contains links to the company's social media profiles.
- It's possible that your website uses a default CSS other than special styling for specific pages. In this case, you can also include a *Default CSS* field in your App config model.
## Want to learn more?
Check out the following guides:
- [More example patterns](/content-modeling/examples)
- [How to create a model in Prepr](/content-modeling/managing-models).
Source: https://docs.prepr.io/content-modeling/examples/app-config
---
# Content modeling examples
These examples will help you gain a good sense on how to model your schema. They explain how to set up commonly used UX patterns. Feel free to copy these examples and adjust them according to your needs.
Source: https://docs.prepr.io/content-modeling/examples
---
# Acme Lease demo website
*This guide covers info about the Prepr CMS - Next.js demo website based on a fictional car leasing company, Acme Lease.*

## Prerequisites
You need to have the following setup before you clone, run and deploy this website from the [GitHub repo](https://github.com/preprio/acme-lease).
- [A free Prepr account](https://signup.prepr.io) with an environment with [demo data](/project-setup/setting-up-environments#create-an-environment)
## About the Acme Lease Demo
This demo website is a real-world example built for Acme Lease, a fictional car leasing company.
It serves as a functional showcase of how to implement a staging website with Next.js and Prepr CMS including a personalized home page and conversion-focused landing pages.
Under the hood, the project leverages the following tech stack designed for speed and scalability:
- *Prepr CMS*
- *Next.js*
- *Apollo Client*
- [*Prepr Next.js package*](/prepr-nextjs-package)
Beyond dynamically rendered content, the demo website highlights Prepr's key marketing features.
You can explore personalized pages tailored to visitor behavior and observe active A/B tests designed to optimize conversion rates.
The site includes an accessible Prepr icon, granting instant access to preview options and experiment testing, to make sure every update is perfect before it goes live.
## Features
The Acme Lease demo website includes the following Prepr CMS features:
### Dynamic content
The [*Dynamic content* field](/content-modeling/field-types#dynamic-content-field) is a flexible editor designed for rich storytelling.
It allows editors to mix and match various elements, such as structured text, headings, tables, embedded assets and components.
It's commonly used for blog articles where you need to intersperse text with images, videos or social media embeds.
The Acme Lease demo website gives you an example on how to render various [dynamic content elements](https://github.com/preprio/acme-lease/blob/main/src/components/blog/blog-content.tsx) to display blog posts.
### Adaptive content
The core personalization engine in Prepr CMS allows marketers to create [adaptive content](/personalization/managing-adaptive-content).
Marketers can create multiple versions of a content element tailored to specific visitor segments, like *Electric Car Lovers*.
Instead of a "one-size-fits-all" approach, the CMS automatically serves the most relevant content variant in real-time based on visitor behavior, location, or data from external CRMs.
Explore how we enable the [Prepr tracking pixel](https://github.com/preprio/acme-lease/blob/main/src/app/%5Blocale%5D/layout.tsx) to show adaptive content to the right segments, like the personalized home page.
The relevant components of the page include [HTML attributes](https://github.com/preprio/acme-lease/blob/main/src/components/sections/hero-section.tsx) to trigger Prepr to calculate metrics for each personalized variant.
### A/B tests
The [A/B test](/ab-testing/running-ab-tests) feature allows marketers to test different versions of a component or text field (Variant A vs. Variant B) directly in Prepr.
By tracking impressions and conversion events (like button clicks) for each variant, marketers can identify which headlines, images, or CTAs perform better before committing to a content variant.
Explore how we enable the [Prepr tracking pixel](https://github.com/preprio/acme-lease/blob/main/src/app/%5Blocale%5D/layout.tsx) to show either the A or B variant to website visitors, like the *Electric lease* landing page.
The relevant components of the page include [HTML attributes](https://github.com/preprio/acme-lease/blob/main/src/components/sections/hero-section.tsx) to trigger Prepr to calculate metrics for each variant.
### Preview toolbar
The [*Preview toolbar*](/prepr-nextjs-package) is a powerful tool included in the Prepr Next.js package.
Content editors and marketers can use it to validate their work.
It appears as a floating Prepr icon on your staging site, allowing them to:
- Switch segments: Manually toggle between visitor segments to see how personalized content looks for each segment.
- Preview A/B Tests: Quickly swap between variant A and B in a page with an A/B test.
- Direct edit links: Click through from the preview page directly to the specific content item in your Prepr environment for instant updates.
### Coding best practices
Based on our experience and discussions with our partners, we've accumulated knowledge on some best practices when coding front-end web apps with Prepr CMS and have included the following practices in this project:
- [GraphQL *Codegen*](https://the-guild.dev/graphql/codegen) - We use this tool to automatically generate code from the the Prepr GraphQL schema and operations.
- [Section *Type* mapping](https://github.com/preprio/acme-lease/blob/main/src/types/sections.ts) - To make sure only developed sections are rendered and each section is rendered in a type safe way.
- [Query fragments](https://github.com/preprio/acme-lease/tree/main/src/queries/fragments) - To remove duplication in queries. Using fragments result in smaller queries and makes it is easier to map to component props.
## Deployment
Go to the public Acme Lease demo [GitHub repo](https://github.com/preprio/acme-lease) to clone this project and follow the installation instructions in the readme.
You can also follow the deployment instructions to deploy to Vercel in one click.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Create a Next.js complete website from scratch](/connecting-a-front-end-framework/nextjs/next-complete-guide)
- [Draft more queries for components and other field types](/graphql-api)
- [Understand the Prepr Next.js package](/prepr-nextjs-package)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/acme-lease-demo
---
# Next.js Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Next.js project to get data from Prepr CMS. You'll learn how to make a simple blog with Next.js and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Next.js project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Next.js and Prepr CMS
## All done
Congratulations! You have successfully connected a Next project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Add A/B testing and Prepr personalization to your Next app](/connecting-a-front-end-framework/nextjs/next-complete-guide)
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use the Next Tailwind module](https://nextjs.org/docs/app/building-your-application/styling/tailwind-css)
- [Deploy your Next app with Vercel](https://nextjs.org/learn-pages-router/basics/deploying-nextjs-app)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-quick-start-guide
---
# Complete guide to Next.js and Prepr
*This guide shows you how to connect Prepr to a Next.js project including styling, adaptive content, A/B testing and a preview bar.*
Follow the steps below in the recommended order to set up your own working Next.js website with adaptive content, A/B testing and a preview bar.
You can also customize this project to fit the requirements for your web app.
Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide
---
# Caching strategies for Next.js and Apollo Client
*This article gives you insight into caching strategies and our recommendation when connecting your Next.js web app with Prepr CMS using Apollo Client.*
## Introduction
Caching is the process of storing copies of data in a temporary storage layer so that future requests for that data can be served faster.
Instead of fetching data from the CMS every time, cached data can be retrieved quickly from a nearby location like memory, a server, or a CDN.
## Caching layers
When connecting your Next.js front end to Prepr CMS using Apollo Client, caching happens at several layers.
### Next.js
There are different caching mechanisms in Next.js, each serving their own purpose:
- *Request Memorization* is only persistent per request cycle and isn’t relevant for Prepr caching strategies.
- *Data Cache* is turned off by default and can be opted in using `{ cache: 'force-cache' }` with the native `fetch` API.
- *Full Route Cache* is enabled by default, but if a route has a `fetch` request that is not cached then this will opt you out of the *Full Route Cache*. Since caching of the data cache is turned off by default, you will also not use the full route cache.
- *Router Cache* is responsible for caching layouts, loading states and pages on backwards and forward navigation.
In your front end you can configure the caching behavior for individual routes and data requests.
If you don't set any caching options when fetching from the API, both the *Data Cache* and the *Full Route Cache* are not active and data is refetched on every request.
For more details, check out the [Next.js caching docs](https://nextjs.org/docs/app/deep-dive/caching).
### Apollo Client
Apollo Client stores the results of your GraphQL queries in a local, normalized, in-memory cache.
This enables Apollo Client to respond almost immediately to queries for already-cached data, without even sending a network request.
For more details, check out the [Apollo Client caching docs](https://www.apollographql.com/docs/react/caching/overview).
### Prepr CDN
All Prepr content is served by a globally distributed content delivery network (CDN).
When you send your first API request to fetch data from Prepr, the response is cached in an edge cache location.
For more details, checkout the [GraphQL API caching doc](/graphql-api/caching).
## Recommendation
To make the most out of the dynamic Prepr features, personalization and A/B testing, we recommend setting up your front end for [SSR (server-side rendering)](/development/best-practices/csr-ssr-ssg#server-side-rendering-ssr).
Check out the [Next.js complete guide](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic) for an example Next.js project using Apollo Client.
## Prepr Next.js SSG example
If you choose not to use Prepr personalization or A/B testing, you can implement a caching strategy in Next.js and Apollo Client to build an SSG (statically generated) website.
Check out the [Prepr Next.js static GitHub repo](https://github.com/preprio/prepr-nextjs-static) for example `page.tsx` code to view the Next.js and Apollo Client cache setup.
This project also includes two webhooks, `api/post-published` and `api/post-updated` which reset the cache if triggered.
To create a simple SSG blog site, follow the steps below.
1. Clone the [Prepr Next.js static GitHub repo](https://github.com/preprio/prepr-nextjs-static).
2. Copy the `.env.example` file to a new `.env` file by running the following command:
```bash
cp .env.example .env
```
3. In the .env file, replace `{YOUR_GRAPHQL_URL}` with the *API URL* of the Prepr *GraphQL* access token from your Acme Lease demo environment.

4. Deploy the app in your preferred deployment tool. You need the deployed URL to set up the webhooks in Prepr in the next step.
5. Configure two webhooks in Prepr to listen for changed and published content and trigger your site to reset the cache.

- Set the **URL** value to `{YOUR_DEPLOYMENT_URL}/api/post-updated`, choose `content-item.changed` for **Events** and choose `Post` for **Models**.

- Set the **URL** value to `{YOUR_DEPLOYMENT_URL}/api/post-published`, choose `content-item.published` for **Events**, and choose `Post` for **Models**.
All done! Now you have a simple SSG blog post site that renders updated content whenever content is changed or published.
## Next steps
To learn more on how to expand your Next.js project, check out the following resources:
- [More data collection details](/data-collection)
- [More about A/B testing](/ab-testing)
- [More about personalization](/personalization)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/caching-strategies
---
# Next.js + Prepr CMS
Need info on Prepr for a Next.js app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr and to set up pages exactly the way your marketers want them.
## Acme Lease demo website
## Next.js Quick start guide
## Next.js Complete guide
## Prepr Next.js package
The Prepr Next.js package enables you to set up A/B testing, personalization, and a preview bar - allowing you to seamlessly test and optimize content for different audience segments in your staging environment.
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to set up A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs
---
# Nuxt Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Nuxt project to get data from Prepr CMS. You'll learn how to make a simple blog with Nuxt and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Nuxt project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Nuxt and Prepr CMS
## All done
Congratulations! You have successfully connected a Nuxt project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Add styling and Prepr personalization to your Nuxt app](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide)
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use the Nuxt Tailwind module](https://nuxt.com/modules/tailwindcss)
- [Deploy your Nuxt app with Vercel](https://vercel.com/docs/frameworks/nuxt)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-quick-start-guide
---
# Complete guide to Nuxt and Prepr
*This guide shows you how to connect Prepr to a Nuxt project including styling, adaptive content, and A/B testing.*
Follow the steps below in the recommended order to set up your own working Nuxt website with adaptive content, A/B testing and a preview bar.
You can also customize this project to fit the requirements for your web app.
Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide
---
# Nuxt + Prepr CMS
Need info on Prepr for a Nuxt app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr and to set up personalized pages exactly the way your marketers want them.
## Nuxt Quick start guide
## Nuxt Complete guide
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs
---
# Laravel Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Laravel project to get data from Prepr CMS. You'll learn how to make a simple blog with Laravel and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Laravel project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
## Create a simple Blog website with Next.js and Prepr CMS
## All done
Congratulations! You have successfully connected a Laravel project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Add styling and Prepr personalization to your Laravel app](/connecting-a-front-end-framework/laravel/laravel-complete-guide)
- [Draft more queries for components and other field types](/graphql-api)
- [Check out the Laravel GraphQL SDK repo](https://github.com/preprio/laravel-graphql-sdk)
- [Deploy your Laravel app](https://devcenter.heroku.com/articles/getting-started-with-laravel#deploying-to-heroku)
Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-quick-start-guide
---
# Complete guide to Laravel and Prepr
*This guide shows you how to connect Prepr to a Laravel project including styling, adaptive content, and A/B testing.*
Follow the steps below in the recommended order to set up your own working Laravel website with adaptive content, A/B testing and a preview bar.
You can also customize this project to fit the requirements for your web app.
Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide
---
# Laravel + Prepr CMS
Need info on Prepr for a Laravel app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr and to set up personalized pages exactly the way your marketers want them.
## Laravel Quick start guide
## Laravel Complete guide
## Laravel SDKs
## Other resources
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel
---
# React + Prepr CMS
This overview page gives you the resources you need to connect your React project to Prepr.
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/react
---
# Vue Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Vue project to get data from Prepr CMS. You'll learn how to make a simple blog with Vue and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Vue project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Vue.js and Prepr CMS
## All done
Congratulations! You have successfully connected a Vue project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind CSS](https://tailwindcss.com/docs/guides/vite)
Source: https://docs.prepr.io/connecting-a-front-end-framework/vuejs/vue-quick-start-guide
---
# Vue.js + Prepr CMS
Need info on Prepr for a Vue app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr.
## Vue.js Quick start guide
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/vuejs
---
# Angular Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to an Angular project to get data from Prepr CMS. You'll learn how to make a simple blog with Angular and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Angular project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with the demo content in Prepr](/project-setup/setting-up-environments#create-an-envirntonment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Angular and Prepr CMS
## All done
Congratulations! You have successfully connected an Angular project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind](https://tailwindcss.com/docs/installation/framework-guides/angular)
- [Deploy your Angular app with Vercel](https://vercel.com/guides/deploying-angular-with-vercel)
Source: https://docs.prepr.io/connecting-a-front-end-framework/angular/angular-quick-start-guide
---
# Angular + Prepr CMS
Need info on Prepr for an Angular app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr.
## Angular Quick start guide
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/angular
---
# PHP Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a PHP project to get data from Prepr CMS. You’ll learn how to build a simple blog with PHP and Prepr CMS. When you reach the end of this guide, you'll have a working app that looks something like the image below.*

## Prerequisites
You need to have the following setup before you connect your PHP project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
## Create a simple Blog website with PHP and Prepr CMS
## All done
Congratulations! You have successfully connected a PHP project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind CSS](https://tailwindcss.com/docs/installation)
Source: https://docs.prepr.io/connecting-a-front-end-framework/php/php-quick-start-guide
---
# PHP + Prepr CMS
Need info on Prepr for a PHP app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr.
## PHP Quick start guide
## PHP SDKs
## Other resources
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/php
---
# Astro Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to an Astro project to get data from Prepr CMS. You'll learn how to make a simple blog with Astro and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Astro project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-envirntonment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Astro and Prepr CMS
## All done
Congratulations! You have successfully connected an Astro project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind](https://tailwindcss.com/docs/guides/vite)
- [Deploy your Astro app with Vercel](https://docs.astro.build/en/guides/deploy/vercel/#adapter-for-ssr)
Source: https://docs.prepr.io/connecting-a-front-end-framework/astro/astro-quick-start-guide
---
# Astro + Prepr CMS
Need info on Prepr for an Astro app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr.
## Astro Quick start guide
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/astro
---
# Svelte Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Svelte project to get data from Prepr CMS. You'll learn how to make a simple blog with Svelte and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Svelte project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Svelte and Prepr CMS
## All done
Congratulations! You have successfully connected a Svelte project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind CSS](https://tailwindcss.com/docs/guides/vite)
- [Deploy your Svelte app with Vercel](https://svelte.dev/docs/kit/adapter-vercel)
Source: https://docs.prepr.io/connecting-a-front-end-framework/svelte/svelte-quick-start-guide
---
# Gatsby Quick start guide
*Estimated duration: 10 minutes*
*This guide shows you how to connect Prepr to a Gatsby project to get data from Prepr CMS. You'll learn how to make a simple blog with Gatsby and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.*

## Prerequisites
You need to have the following setup before you connect your Gatsby project to Prepr.
- [A free Prepr account](https://signup.prepr.io)
- [An environment with demo data in Prepr](/project-setup/setting-up-environments#create-an-environment)
- [The latest version of Node.js](https://nodejs.org/en)
## Create a simple Blog website with Gatsby and Prepr CMS
## All done
Congratulations! You have successfully connected a Gatsby project to Prepr for a simple Blog app.
## Next steps
To learn more on how to expand your project, check out the following resources:
- [Draft more queries for components and other field types](/graphql-api)
- [How to install and use Tailwind](https://tailwindcss.com/docs/guides/vite)
Source: https://docs.prepr.io/connecting-a-front-end-framework/gatsby/gatsby-quick-start-guide
---
# Svelte + Prepr CMS
Need info on Prepr for a Svelte app?
Look no further.
This all-in-one page gives you all the resources you need to connect your project to Prepr and to set up personalized pages exactly the way your marketers want them.
## Svelte Quick start guide
## Other resources
- [Rendering strategies, SSR or SSG?](/development/best-practices/csr-ssr-ssg)
- [How to set up personalization](/personalization/setting-up-personalization)
- [How to measure A/B testing](/ab-testing/setting-up-ab-testing)
Source: https://docs.prepr.io/connecting-a-front-end-framework/svelte
---
# Working with assets
Follow these guidelines to help you include images, videos, audios, and files in your web applications.
Source: https://docs.prepr.io/development/best-practices/assets
---
# CSR/SSR/SSG Rendering strategies
*This article explains different rendering strategies for front-end apps and makes recommendations on how to implement your strategy with Prepr.*
## Introduction
It's important to decide on a rendering strategy for your front-end apps in the early stages of your implementation. The strategy you choose should match the type of content that your front end renders. For example, do you need to render a lot of static content such as documentation or urgent dynamic content like on an e-commerce site. We look at different types of rendering and any special considerations when implementing your front end alongside Prepr.
## Rendering types
|Rendering type| Applicable Technologies |
|-------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|[Client-side rendering (CSR)](#client-side-rendering-csr) The original way to render web pages with dynamic content when JavaScript was first introduced. When a user visits a page, they see it only after the script has finished.| [React](/connecting-a-front-end-framework/react), [Vue.js](/connecting-a-front-end-framework/vuejs), [Angular](/connecting-a-front-end-framework/angular), [Next.js](/connecting-a-front-end-framework/nextjs), [Nuxt](/connecting-a-front-end-framework/nuxtjs). |
|[Server-side rendering (SSR)](#server-side-rendering-ssr) The server generates the HTML on a request for a page. This means that when a user navigates to a page, they will see a fully rendered UI immediately.| [React](/connecting-a-front-end-framework/react), [Vue.js](/connecting-a-front-end-framework/vuejs), [Angular](/connecting-a-front-end-framework/angular), [Next.js](/connecting-a-front-end-framework/nextjs), [Nuxt](/connecting-a-front-end-framework/nuxtjs), [Node.js](/connecting-a-front-end-framework/nodejs). |
|[Static site generation (SSG)](#static-site-generation-ssg) A bunch of static files for the entire site are generated during deployment. This means that a visitor can see and interact with the pages immediately.| [React](/connecting-a-front-end-framework/react), [Vue.js](/connecting-a-front-end-framework/vuejs), [Angular](/connecting-a-front-end-framework/angular), [Next.js](/connecting-a-front-end-framework/nextjs), [Nuxt](/connecting-a-front-end-framework/nuxtjs), [Node.js](/connecting-a-front-end-framework/nodejs). |
|[Hybrid rendering solutions](#hybrid-rendering-solutions) Some frameworks offer a hybrid rendering solution that uses the best of both SSR and SSG. | [See below](#hybrid-rendering-solutions) for more details on the hybrid solutions offered by [Next.js](/connecting-a-front-end-framework/nextjs), [Nuxt](/connecting-a-front-end-framework/nuxtjs). |
## How to choose a rendering type
It is important to think about how frequently your content changes and how urgent these content changes are. For example, a blog site does not usually require multiple updates in a day, so static generation is a good option. On the other hand, product information on an e-commerce site needs frequent updates, so rendering needs to happen more dynamically.
Below are other metrics to consider when you choose a rendering strategy.
|Metric|CSR|SSR|SSG|Hybrid|
|----------|-------|-------|-------|-------|
|**Data integrity** How up to date the data is when a page loads.| | | | |
|**SEO** How easy it is for search engines to find the page content.| | | | |
|**Performance** How quickly a page loads. | | | | |
|**Build Time** How quick it is to build an app. | | | | |
Watch the video below for the key differences betweens SSG and SSR.
## Client-side rendering (CSR)
Client-side rendering (CSR) is rendering pages directly in the browser for every page request using JavaScript. This type of rendering is mainly used for single-page applications (SPA) because the single page needs to be refreshed each time it's loaded. This means the data is always up to date, but large payloads will slow down the loading of a page.

## Server-side rendering (SSR)
Server Side Rendering (SSR), also known as dynamic rendering, is when the HTML of a site is generated on the server, then sent to the browser. This type of rendering is faster than CSR for large payloads and is useful for SEO purposes, because search engines can access the content. See a simple SSR process flow below.

## Static site generation (SSG)
SSG is a type of pre-rendering where the process of compiling and rendering a web app happens during the build time. The output of the build is a bunch of static files, including the HTML file as well as assets like JavaScript and CSS. Updates to pages are not rendered until a new build. Because all the pages are pre-rendered, the page load is faster than SSR, but any changes to content will not be re-rendered on the fly.

## Hybrid rendering solutions
A hybrid rendering solution gives developers the option to get benefits from both SSR and SSG. The following solutions are available in a few frameworks:
- **Page-by-page**: This means that each page of your project can be rendered either statically or dynamically. This method is available in Next.js. Check out the [Next.js](https://nextjs.org/docs/pages/building-your-application/rendering) docs for more details.
- **Route-based rendering**: This solution allows you to render specific routes (URL paths) statically or dynamically. The route can be at subdomain level which means that groups of pages can be rendered statically or dynamically. Check out the [Next.js docs](https://nextjs.org/learn-pages-router/basics/dynamic-routes) and the [Nuxt docs](https://nuxtjs.org/docs/features/rendering-modes) for more details.
- **Incremental static regeneration (ISR)** and **Deferred static generation (DSG)**: These hybrid solutions aim to use the best of both SSR and SSG. When a user visits a page, the front end triggers the regeneration (also known as revalidation) of the page, but the user sees the *static page* immediately. If the user or another user visits the same page a few seconds later, the newer page is rendered. Unlike SSG, you can choose the number of pages to build to reduce the build time and performance is better than SSR because the request does not wait for the rendering of a page to complete. ISR was developed by Next.js on Vercel while DSG is the Gatsby solution. Another version of this solution is possible in Nuxt deployed on Layer0. See a simple process flow below: 
## Schedule a free consultation
Do you still have questions on rendering strategies in relation to Prepr? Book a 15-minute call with a Prepr solution engineer right away. [Schedule a call](https://prepr.io/get-a-demo)
Source: https://docs.prepr.io/development/best-practices/csr-ssr-ssg
---
# Handling redirects
*This article explains how to handle redirects for your content items in Prepr CMS*
## Introduction
Redirects send visitors from a requested URL to another. You often set up redirects in your framework-specific front-end app or in a redirects file for a hosting provider for pages that are broken or pages that were moved to new URLs to ensure visitors and search engines access the most relevant or current page.
## Handle redirects with a headless CMS
It's only natural that content items can change. When the changes include the URL that links to the content item, this results in a broken link. To prevent this situation, a developer sets up a redirect to display a working page when an outdated link is visited.
In the case where you have content items that could potentially have changes to the URL that links to it, for example, when updating an existing article with fresher content including the name of the link to the article, follow the steps below to reduce the number of broken links in your front end.
## Step 1: Model the redirect in Prepr CMS
The first step is to model the redirect to make it possible to manage redirect entries directly in Prepr CMS.
The *Redirect* model includes the following fields:
- The outdated URL, often known as the *Source*.
- The new target URL, known as the *Destination*.
- An indicator to choose the type of redirect, for example, `permanent` or `temporary`.
See the examples below for typical redirect config in a front-end framework like Next.js and for server redirect config like a Vercel deployment.
A slug is the end part of a URL after the last backslash and identifies a unique page in a front end.
In Prepr CMS, you can create a [slug field](/content-modeling/field-types#slug-field) in a model to maintain a unique value for each content item.
This slug value is then used in your front-end app to set up page routing to that content item. Check out the [Next Quick start guide](/connecting-a-front-end-framework/nextjs/next-quick-start-guide#step-4-fetch-individual-articles) for an example implementation.
With this in mind, follow the steps below to create a *Redirect* model.
1. Click the **Schema** tab to open the **Schema Editor**.
2. Then, click the **+ Add model** button.
3. Click **Multi-item model** and **Next** again.
4. Enter *Redirect* as the *Name* and click **Save**.
5. Add a *Text* field type to save the *Internal title* to easily identify a redirect record.
6. Drag and drop the *Slug* field type into your model.
Switch to the **Validation** tab and enable the **This field is required** toggle.
7. Drag and drop the *Content reference* field type, from the list on the right into your model.
a. Enter *Destination* as the *Name*.
b. Select the models you want to allow to have redirects.
c. Switch to the **Validation** tab and enable the **This field is required** toggle.
d. Click the **Save** button.
8. Drag and drop the *Boolean* field type into your model and enter *Permanent* as the *Name*, set a *Default value* of **True** and click the **Save** button.

Now that the *Redirect* model is done, move on to the next step to add redirect entries in Prepr CMS.
## Step 2: Create a redirect in Prepr CMS
Follow the instructions below to add a redirect entry manually.
1. Go to the **Content** tab.
2. Click **Add item** and select the **Redirect** model created in the previous step.
3. Enter the *Slug* of the outdated URL in the format expected by your framework or host redirects file.
4. For the *Destination* field, choose the relevant content item for which the slug was changed.
5. Enable the permanent field, if applicable, and click the **Publish** button.

That's it! Once the redirect entries are added to Prepr, you can then fetch the entries and process them.
## Step 3: Handle redirects
This guide outlines two methods to handle redirects. One is based on handling redirects in a Next.js project by dynamically adding the redirects to the `next.config.js` file. The other is handling redirects in an Astro project by adding the redirects to the `vercel.json` which gets picked up and processed when the project is deployed in Vercel.
Follow the steps below to create a script to fetch the redirects info from Prepr CMS and generate the redirects to either be included in the `next.config.js` or written to the `vercel.json`.
1. Create the script `getRedirects` to fetch the redirects like in the code snippets below. Set the placeholder value for `