# 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. ![quick-start-guide-use-case](https://assets-site.prepr.io/w_1920/4e2edea6-dbeb-4ae8-bd2c-f78ebf6ace7e.jpg) ## 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**. ![add environment](https://assets-site.prepr.io/ki6nbcjodkg//updated-navigation-add-new-environment.png) 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**. ![Start from scratch](https://assets-site.prepr.io/19le7vlh9jx1//updated-navigation-environment-start-from-scratch.png) 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. ![quick-start-guide-create-content-model](https://assets-site.prepr.io/w_1920/5c7b4cee-65ee-493b-8df8-58477e39e81f.jpg) Let’s create these models in Prepr: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Then, click the **+ Add model** button. 3. Choose **Start from scratch**, click **Next**, choose **Multi-item model**, and click **Next**. 4. 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. ![empty person model](https://assets-site.prepr.io/68oq98b6ooov//empty-person-model.png) 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: ![quick-start-guide-person-model](https://assets-site.prepr.io/6ueyg6ol7k27//person-model-with-fields.png) Now you can add the Article model. 1. Click the **+ Add model** button on the left. 2. Choose **Start from scratch**, click **Next**, choose **Multi-item model**, and click **Next**. 3. 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: ![Empty article model](https://assets-site.prepr.io/28cn97h2ebdg//empty-article-model.png) 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**. ![ Article model with author ](https://assets-site.prepr.io/hyvn5yhhjwi//article-model-with-fields.png) 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. ![Article model completed](https://assets-site.prepr.io/6p0d1ttiqyzb//article-model-with-all-fields.png) ## 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. ![create a person](https://assets-site.prepr.io/vfavn56rrwb//example-person.png) 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. ![create article](https://assets-site.prepr.io/38x1tn6pm1x1//example-article.png) 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. ![GraphQL production access token example](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) Make sure you see a green dot and your access token at the end of the url. If you cannot connect, please contact support. ![API explorer example](https://assets-site.prepr.io/350zhceg8aek//api-explorer-example.png) 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) - [Gatsby](/connecting-a-front-end-framework/gatsby) - [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 customer experience. 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** | [2024](/stay-updated/changelog2024) | [2023](/stay-updated/changelog2023) ## Introducing goals for personalization and A/B testing *December 17th, 2025* Goals allow you to see the overall impact of your personalization and A/B testing experiments on conversions. You can create clear conversion definitions by combining multiple behavioral conditions. ![Goal example](https://assets-site.prepr.io/71wpirc8sycj//example-primary-goal.png) This means you can optimize your website not just for click-through rate (CTR), but for deeper insights. So you can better understand what works for customer experience, boosting engagement and conversion rates. Check out the [Goals setup guide](/personalization/defining-goals) for more details. ## New *Content tree* layout *December 16th, 2025* You can now view your overall structure of content items, by their slug (URL) value, as a visual tree layout. The *Content tree* layout provides instant, hierarchical context for how an item relates to other content. ![Content tree example](https://assets-site.prepr.io/5ur92tb7k8ym//content-tree-example.png) This means improved navigation between content items and less time searching for related items. For more details, check out the [content tree setup guide](/project-setup/setting-up-environments#content-tree-parent-slug-format). ## Generate AI suggestions for personalized variants *December 9th, 2025* When adding personalized content, you can now get AI suggestions for adaptive content based on a customer segment you choose. The auto-generated variant suggestions give you inspiration to quickly create and fine-tune your adaptive content. ![Auto generate variants gif](https://downloads-site.prepr.io/2ftxb98gurhz-create-ai-variants.gif) The AI generation of adaptive content allows you to automate normally repetitive work of re-writing content for multiple customer segments. This means you can scale your personalization efforts in much less time. Check out the [Adaptive content guide](personalization/managing-adaptive-content#add-an-adaptive-content-element) for more details. ## Dynamic initial values for text fields *December 8th, 2025* With dynamic initial values you can set up text fields to prefill based on other field values helping editors speed up content creation. For example, for *Post* content items, you can define the initial value for the SEO meta description field to be prefilled with the Post excerpt value the editor enters in the content item. ![Dynamic initial value example setting](https://assets-site.prepr.io/285n86l2t9ap//text-field-settings-populated-initial-value.png) This means simpler data entry and ensures consistency across content items. Check out the [text field settings](/content-modeling/field-types#text-field) for more details. ## Improved GraphQL caching *November 27th, 2025* We've improved our GraphQL API caching mechanism to significantly improve developer experience and workflow reliability when making changes to your *Schema*. Now, the GraphQL API automatically refreshes the cache when you make any change to a schema. This means that your changes are immediately applied when you regenerate your TypeScript types in front-end application. Check out the [GraphQL API caching doc](/graphql-api/caching) for more details. ## Introducing granular permissions to manage content items *November 24th, 2025* With granular content permissions, you can now precisely define a user role to allow users to only create, read, update, delete, manage comments, publish and unpublish content items. ![Organization user management - content role permissions](https://assets-site.prepr.io/51ods7lboki7//organization-user-role-content-permissions.png) In doing so, you have enhanced security and clearer workflow for every user reducing the risk of accidental errors. Check out the [user role guide](/project-setup/managing-roles-and-permissions#add-or-edit-roles) for more details. ## Prepr now available in French *November 24th, 2025* With Prepr now available in French, your users in French-speaking regions or those who prefer French can use Prepr in their native language. You can enable the French UI in the environment settings or each user can set their preferred interface language to French in their [account profile](/project-setup/managing-users#set-language-preferences). ![Environment settings - Choosing French UI](https://assets-site.prepr.io/1ifjig2xve8b//environment-setting.png) This feature provides a more intuitive and comfortable user experience, leading to greater understanding, and reduced errors for French-speaking users. For more details, check out the [environments settings](/project-setup/setting-up-environments#manage-environment-settings). ## Making slug prefix read-only *November 5th, 2025* We've introduced a new option to make the first part of a slug read-only. When you enable this option in the *Slug* field settings, editors can only edit the part of the slug after the last `/`. ![new read-only slug prefix option](https://assets-site.prepr.io/39hv69dp8wen//example-slug-settings-with-new-option-highlighted.png) With this feature, you enforce consistent slugs ensuring clean and accurate content item URLs and prevent broken links when editors need to update slug values manually. Check out the [*Slug* field reference](/content-modeling/field-types#slug-field) for more details. ## Conditional visibility by environment *October 23rd, 2025* You can now control field visibility per environment when using a shared schema. This new option lets you choose which environments to show certain fields, ideal for multi-site or multi-brand setups where fields differ slightly between environments. ![Conditional visibility by environment toggle](https://assets-site.prepr.io/ey2e2n6oi4u//conditional-visibility-option-by-environment.png) It makes managing shared schemas much more flexible and keeps your content models clean and relevant across all sites. Check out the [shared schema guide](/project-setup/architecture-scenarios/shared-schema#choose-field-visibility-for-environments) for more details. ## New SSO login options *October 23rd, 2025* You can now integrate your preferred identity provider (IdP) to Prepr using one of our new SSO options. In addition to *Microsoft Entra ID* (formerly *Azure Active Directory*), you can now set up single sign-on for your Prepr users using *Google Workspace*, or any identity provider with either the *SAML 2.0* or *OpenID Connect* open standards. ![new integration page with SSO options highlighted](https://assets-site.prepr.io/7ek44rewu8i9//new-sso-options-integration-page.png) By setting up one of these options, you enhance security and give your users an improved login experience. Check out the [updated SSO guide](/project-setup/setting-up-sso) for more details. ## Improved navigation user interface *October 21st, 2025* We've improved our navigation with a cleaner and more intuitive interface. The environment selector is now on the left and you'll see a prominent banner to indicate when you're logged into a test or development environment. You'll also find the *Settings* in a new location on the right when you click the icon. ![updated navigation UI](https://assets-site.prepr.io/4k2dflyaf6f3//updated-navigation.png) The updated navigation allows you to work more confidently in Prepr with the clear indication of the environment and type of environment you're working in. For more details, check out the [environments guide](/project-setup/setting-up-environments). ## Publish nested content items *October 21st, 2025* You now have the option to publish all linked child items in one go when publishing a parent content item. ![publish child items gif](https://downloads-site.prepr.io/4ooirmjcsywc-publish-nested-items.gif) This prevents broken or incomplete pages and ensures all linked content goes live at the same time. So, you save time and avoid errors by publishing the whole content structure in a single action. Check out the [content management docs](/content-management/managing-content/managing-content-items#publish-a-content-item) for more details. ## Introducing filter options for content selection *October 16th, 2025* You can now see filter options in the content item selection modal when you choose to add related content items to your content item. ![Content item modal example with filter options](https://assets-site.prepr.io/66g35692of4g//new-content-item-modal-with-example-filter.png) These options allow you to quickly narrow down large lists of content items by key criteria like model, category, or workflow stage. So, you save time and ensure you link related content items more accurately. Check out the [adding content references doc](/content-management/managing-content/creating-rich-content#adding-content-references) for more details. ## Introducing custom workflow stages *October 8th, 2025* We've added the ability for you to add custom workflow stages to your Prepr collaboration workflow on the *Environment* detail page. For example, when you have translation tasks for content items, you could add stages like *Translate* and *Review translation*. ![Add custom workflow gif](https://downloads-site.prepr.io/5ye88rqx03r2-add-custom-workflow-stage.gif) This means you can seamlessly align the Prepr workflow with your own content creation process. For more details, check out the [environment settings doc](/project-setup/setting-up-environments#workflow-stages). ## New GraphQL API version 2025-10-07 is available *October 7th, 2025* Our newest GraphQL API version brings you additional localization support with the following new features: - A new root query field `DefaultLocale` returns the environment's default locale. - `_locale` in the Interface `Model` - `_locales` in the Interface `Model` Check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide#version-2025-10-07) for more details. ## Introducing the Shopify integration *October 2nd, 2025* Our new Shopify integration lets your team easily include products, variants and collections in content items. ![Example Shopify remote content search](https://assets-site.prepr.io/796ea4l3c69s//search-for-shopify-products.png) This means your content editors can work more efficiently and error-free by simply choosing the relevant Shopify entries directly in Prepr. For more details, check out the [Shopify integration guide](/integrations/shopify). ## Introducing the BigCommerce integration *October 2nd, 2025* Now you can integrate Prepr with BigCommerce to seamlessly add product details to your content. ![Example BigCommerce remote content search](https://assets-site.prepr.io/2vg1o9rvga6g//search-for-bigcommerce-products.png) With this integration, your content editors can save time by simply choosing BigCommerce products directly in Prepr. For more details, check out the [BigCommerce integration guide](/integrations/bigcommerce). ## Automatically review your content items *October 1st, 2025* Introducing *Content check*, a new feature that automatically validates the quality of your content and provides AI-powered suggestions for improvements. ![Content checker feature](https://assets-site.prepr.io/6yn2nvay1v4e//content-checker-feature.png) In just one click, it checks for missing required fields, broken links and options to boost your SEO. Try out this new tool, part of our continuous efforts to optimize the quality of the content in less time, and [let us know your thoughts](https://prepr.io/feedback). Check out the [Reviewing content guide](/content-management/reviewing-content#content-check) for more details. ## Introducing the Snitcher integration *September 15th, 2025* With the new Snitcher integration, you can easily connect Prepr to Snitcher, a B2B website visitor identification platform. This integration allows you to segment website visitors based on their company profile. ![Snitcher filter options](https://assets-site.prepr.io/33peoi8thkyn//snitcher-filter-options.png) So, you can personalize content for an enhanced user experience for your B2B audience. Check out the [Snitcher integration guide](/integrations/snitcher) for more details. ## New sign-in option to use passkeys *September 10th, 2025* We've released a new sign-in option to use passkeys. ![use passkeys](https://assets-site.prepr.io/497us62x3e9v//passkey-option.png) This feature gives you an alternative to using the email, password combination and 2FA. This means you can log in securely and conveniently without needing to manually manage passwords or additional authentication steps. For more details, check out the [account profile settings](/project-setup/managing-users#add-passkeys). ## New option to hide models from *Add item* list *September 3rd, 2025* You can now simplify the content creation experience by reducing the list of models content editors need to select from. To make this possible, choose which models to hide from the selection list in the *Add item* modal. For example: Hide models for child content items like an *Author* or *Category* which are usually created when editing an *Article*. ![Hide model toggle](https://assets-site.prepr.io/4unhkcvkusp1//hide-model.png) By disabling the visibility of certain models, you ensure content editors only see what's relevant to them. Check out the [Model settings](/content-modeling/managing-models#settings) for more details. ## Organize your segments into folders *August 28th, 2025* You can now group your segments into folders, making it easier to manage and navigate when working with many customer profiles. Instead of scrolling through a long alphabetical list, related segments can be organized together in a structured way. ![organize segments gif](https://downloads-site.prepr.io/7egmne226mra-organize-segments.gif) This update gives you a simple way to stay organized and find the right segment faster. For more details, check out the [Managing segments guide](/personalization/managing-segments#organize-segments-into-folders). ## Matching HubSpot contacts to Prepr customer profiles *August 25th, 2025* Prepr now automatically matches your HubSpot contacts to existing Prepr customer profiles, putting them in their matching HubSpot segments and updating their company name and email address. This way, you ensure your HubSpot customer profiles are always accurate and up to date. ![Matching HubSpot contacts](https://assets-site.prepr.io/6scm74kabwat//matching-hubspot-contacts.png) With this release, you can create personalized, data-driven content even more precisely. Check out the [HubSpot integration](/integrations/hubspot) guide for more details. ## Algolia Auto sync option *August 20th, 2025* With the new Algolia **Auto sync** option you can choose to disable automatic synchronization of content to Algolia directly in Prepr. ![Algolia auto-sync option](https://assets-site.prepr.io/12jl199tk88s//algolia-integration-auto-sync-option.png) This gives you more control and helps you prevent issues with the web app search functionality resulting from bulk updates, for example. In other words, ensure a stable search experience for your users. Check out the [Algolia integration guide](/integrations/algolia#connect-prepr-to-algolia) for more details. ## A/B testing article headlines *July 30th, 2025* You can now run experiments for article headlines by adding an A/B test directly to a header or title *Text field*. For example, to test headlines in a list of recommended articles on the home page. Now you can measure which headlines encourage readers to open the article they want to read. ![A/B text field example](https://assets-site.prepr.io/ggs6l74t9o3//ab-test-on-post-title-example.png) Optimize performance with surgical precision, driving higher engagement and conversion rates. To enable A/B testing on a text field check out the [Text field settings](/content-modeling/field-types#ab-testing). ## New Prepr Next.js package version is available *July 22nd, 2025* We're happy to bring you a new and improved version of the **Prepr Next.js package**, a toolkit to streamline your personalization and A/B testing implementation for your Next.js front end. We’ve redesigned the *Preview Bar* into a less intrusive floating toolbar, giving content editors a cleaner, distraction-free preview experience. ![Prepr toolbar gif](https://assets-site.prepr.io/545864k940pz//prepr-preview-toolbar.png) In addition to previewing different A/B test variants and personalized experiences, content editors can now enable **Edit mode** to highlight any element in the preview page. When enabled, they can then simply hover over elements to reveal links that open the corresponding item directly in Prepr for quick updates. Check out the [Prepr Next.js package guide](/prepr-nextjs-package) for more details. ## Improved handling of conditional required fields *July 18th, 2025* We’ve released an important update to ignore the required field validation when a field is conditionally hidden. Previously, if a required field was hidden due to conditional logic, it would still prevent a content item from being published. This often led users to mark fields as non-required simply to avoid validation errors during publishing. With today’s update, a required field is only enforced when it is visible to the content editor. If the field is hidden due to a conditional setting, it'll be treated as not required in the API schema. However, fields that are always visible remain required both in the editor and the API. ![Ignore hidden required field](https://downloads-site.prepr.io/334kmd9g3ofc-ignore-hidden-required-fields.gif) This improvement is enabled by default for new customers, while existing environments can activate the feature manually in the **Environment** settings page. Check out the [environment settings](/project-setup/setting-up-environments#manage-environment-settings) for more details. ## Introducing content item views *July 16th, 2025* With the new content item views, we're introducing a cleaner interface to manage content visibility. This new feature allows you to create, organize, and access your own tailored views. ![content list views example](https://assets-site.prepr.io/b0owkhy5rws//content-list-view-shared-view-in-folder-selected.png) The new content item views replace how you previously used saved filters for content items. You can save time by creating views that are most relevant for you, while your team can collaborate more effectively with shared and role-based views. Check out the [managing content doc](/content-management/managing-content/managing-content-items#views) for more details. ## Introducing the *Needs attention* overview *July 16th, 2025* To enhance the reliability and quality of stored content, we've added a content quality checker to find content items with broken links or content items that could not be published. You can find the list of these content items in the new *Needs attention* view. ![content list view example](https://assets-site.prepr.io/3711hv6qsrnh//needs-attention-view.png) These quality indicators help prevent broken user experiences on live websites and empower content teams to quickly identify and resolve issues before publication. Check out the [managing content doc](/content-management/managing-content/managing-content-items#manage-content-quality) for more details. ## Recovering deleted content items *July 16th, 2025* With the new *Deleted* view, you can now quickly find and restore deleted items with just a few clicks, for example, if you deleted an item accidentally. ![recover deleted items example](https://assets-site.prepr.io/5ok2ngnitu1x//deleted-view.png) Check out the [managing content doc](/content-management/managing-content/managing-content-items#recover-a-deleted-item) for more details. ## Two-factor authentication (2FA) required for Owners and Admins *July 1st, 2025* To strengthen account security, 2FA is required for all users with an *Owner* or *Admin* role in a paid Prepr organization as of July 1, 2025. If 2FA is not enabled, users will be prompted to set it up before accessing Prepr. SSO users are exempt from this requirement. Check out the [Activating two-factor authentication](/project-setup/managing-users#activate-two-factor-authentication) guide for more details. ## New Identify event to store identity provider user IDs *June 25th, 2025* The new `Identify` event stores a user's unique ID from your Identity Provider directly in their matching customer profile in Prepr. ```js copy prepr('event', 'Identify', 'external-profile-ID'); ``` This event allows you to accurately link customer data when they log in to your web app giving you more precise data analysis. For more details, check out the [recording events doc](/data-collection/recording-events#using-identify-providers). ## Introducing the Pipedrive integration *June 24th, 2025* With the new Pipedrive integration, you can embed Pipedrive forms directly into your content items. ![Example contact with Pipedrive form field](https://assets-site.prepr.io/5deedvrnki6f//contact-with-pipedrive-form.png) This means you keep your content and related Pipedrive forms in one place. Just enter the matching Pipedrive form URL to link the form you need. Check out the [Pipedrive integration doc](/integrations/pipedrive) for more details. ## New PATCH mutation endpoint in public beta *June 24th, 2025* We’ve introduced a new `PATCH` endpoint for content items in the Mutation API, allowing you to update just a single field in an existing item instead of replacing the whole object. This aligns with HTTP PATCH best practices for partial updates and efficiency. Plus, thanks to refined metadata handling, this endpoint won’t trigger the `changed_on` timestamp — so batch updates no longer clutter the editor interface. For more details, check out the [Mutation API doc](/mutation-api/content-items-create-update-and-destroy#patch-a-content-item). ## Introducing the Dealfront (Leadfeeder) integration *June 18th, 2025* We’re excited to introduce a new B2B integration in Prepr with Dealfront. This powerful new integration lets you segment website visitors based on their industry and company size. ![Dealfront segment](https://assets-site.prepr.io/78srozr6bacp//dealfront-segments.png) This allows you to personalize content for an enhanced user experience for your B2B audience. For more details, check out the [Dealfront integration guide](/integrations/dealfront). ## New enumeration JSON editor *June 11th, 2025* We've introduced a new option to add or edit enumeration values using a JSON editor. ![Enumeration JSON editor](https://assets-site.prepr.io/6qmyi5h2gtqf//enumeration-json-editor.png) This new option enables you to quickly access and copy the data structure and add your own updated JSON. This saves time, especially when you need to add or edit an enumeration with an large list of values. Check out the [enumerations doc](/content-modeling/managing-enumerations) for more details. ## Personalization across all Stack fields *June 3rd, 2025* Previously, you could add personalization and A/B test content only to a stack field directly included in the model. We've enhanced the *Stack* field to allow personalization and A/B test content at any level in the content structure. These include stack fields in components and within dynamic content fields. For example: In a CTA button component to only personalize the button instead of the whole section of the content item where it's used. ![stack in component example](https://assets-site.prepr.io/3v2oep8fftm8//personalized-button.png) This feature gives you more flexibility for adaptive content in the web app and an improved user experience. To use this feature, make sure to use the newest [GraphQL API version 2025-05-27](/graphql-api/upgrade-guide#version-2025-05-27). ## Dynamic content in components *June 3rd, 2025* Previously, you could only add a dynamic content field to a model. It's now possible to add a *Dynamic content* field to a component to add rich content sections to your section-based pages. For example, to publish a guide with your chosen styling. ![image](https://assets-site.prepr.io/7jzx4povaxrs//dynamic-content-in-component-example.png) This feature allows more flexibility when editing content and more dynamic content delivery in the web app. To use this feature, make sure to use the newest [GraphQL API version 2025-05-27](/graphql-api/upgrade-guide#version-2025-05-27). ## New GraphQL API version 2025-05-27 is available *May 27th, 2025* Our newest GraphQL API version brings you more flexibility when creating a schema and developing an adaptive web app with the following new features: - Support for A/B tests and adaptive content elements within *Stack* fields in components, allowing for more dynamic content delivery and an improved user experience. - The *Dynamic Content Editor* field is now available in components, enabling you to create engaging and personalized content easily. - We’ve introduced the *Tags* field in components, providing a flexible way to categorize and manage your content more effectively. - You can now access a default query to retrieve the locales available in your environment, making it easier for you to implement localization in your front end. - We've enhanced sorting on `string` fields to be case-insensitive, ensuring a more intuitive and user-friendly experience. Check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide#version-2025-05-27) for more details. ## Setting an initial value for *Stack* field *May 13th, 2025* It's now possible to add elements such as specific content items and components to the initial value of a *Stack* field. This release also allows you to add an initial value to a [*Content reference* field](/content-modeling/field-types#content-reference-field). With this feature, you get a suggested outline when you create more complex content items such as pages with many possible elements. For example, when you create a new *Page* content item, you could get a preselected *Hero* component, *Feature* component and a *Call to action* item. ![Stack initial value exampl](https://downloads-site.prepr.io/7roeectn9p-content-stack-with-prefilled-values.gif) This allows you to create consistent and structured content, and saves you time and reduces errors. Check out the [*Stack* field setup](/content-modeling/field-types#stack-field) for the setup details. ## Improved content item filtering *May 13th, 2025* We've added the **Unpublished changes** option to the *Publication status* filter. This addition joins the existing filters for *Published*, *Scheduled*, and *Not published* items, giving you better control and visibility over draft updates. You can use this filter option in the list, calendar, and kanban views to streamline your content management workflow. Check out the [content management doc](/content-management/managing-content/managing-content-items#publication-status) for more details. ## Support for dates and location fields in Algolia and Typesense integrations *May 8th, 2025* The Prepr search integrations with Algolia and Typesense now support date fields and location fields. This update enables more flexible filtering options, such as showing nearby events or sorting content based on dates, making the integration more useful for time-based and location-based use cases. Check out the [Algolia docs](/integrations/algolia) and [Typesense docs](/integrations/typesense) for setting up the integration with dates and location fields. ## Two-factor authentication (2FA) required for Owners and Admins starting July 1, 2025 *May 8th, 2025* To strengthen account security, 2FA will be required for all users with an *Owner* or *Admin* role in a paid Prepr organization as of July 1, 2025. If 2FA is not enabled by that date, users will be prompted to set it up before accessing Prepr. SSO users are exempt from this requirement. Check out the [Activating two-factor authentication](/project-setup/managing-users#activate-two-factor-authentication) guide for more details. ## Improved document naming and URL structure *May 6th, 2025* We're pleased to let you know that we've improved how document files are named and how their URLs are set in Prepr CMS. Now when you upload new documents (pdf, zip, docx and xlsx), they retain their original file name. The URL to download a document includes a cleaner prefix after the hostname, providing a more structured and consistent format for better organization and readability. **Example** Previous URL structure: `https://example.files.prepr.io/695a4d1eiaom-sustainability-report.pdf` New URL structure: `https://example.files.prepr.io/695a4d1eiaom/sustainability-report.pdf` These changes make it easier for you to manage these assets, better visibility, and they align with SEO best practices. Check out the [Editing assets doc](/content-management/managing-assets/managing-assets#editing-assets) for more details on documents fields. ## Sending events to Google Tag Manager *May 1st, 2025* It's now possible to send experiment-related Prepr events to Google Tag Manager (GTM). This is a seamless integration of Prepr's experiment data with your existing GTM setup, giving you centralized tracking. To enable the integration to GTM, simply update the *Prepr Tracking Code* in your front end to include the *googleTagManager* destination flag. Check out the [tracking setup doc](/data-collection/setting-up-the-tracking-code#sending-events-to-google-tag-manager-gtm) for more details. ## Introducing content item calendar view *May 1st, 2025* With the content item calendar view, you can now easily manage your scheduled content directly within a calendar interface. With this clear, visual overview of all your scheduled items, it's now easier to manage timing and avoid overlaps saving time and keeping you organized. ![Content item calendar view](https://assets-site.prepr.io/5i2ykbsoya4g//calendar-view.png) For more details, check out the [content management doc](/content-management/managing-content/managing-content-items#calendar) ## Publication status in content item list *April 18th, 2025* We’ve updated the content item list display for content reference fields, stack fields and their corresponding search dialogs to display the publication status instead of the workflow stage. Now when you view these fields or add a content item for a content reference or stack field, you can easily see which of the listed content items are published or not. ![content item list display - stack field example](https://assets-site.prepr.io/6bfnmcdvzayh//content-item-list-in-stack-field-example.png) ![content item search dialog](https://assets-site.prepr.io/64w1565e9rf5//content-item-search-list-dialog.png) This change helps reduce confusion, and gives you clearer and more actionable information. Check out the [content management docs](/content-management/managing-content/managing-content-items#publication-status) for more details on the publication status. ## Setting a personal default locale *April 17th, 2025* Users can now set a personal default locale that overrides the environment’s default. This is especially useful for international teams, giving editors a more tailored experience when working with multilingual content. ![user settings](https://assets-site.prepr.io/400i56p2kdlc//user-default-locale-setup.png) Check out the [localizing content docs](/content-management/localizing-content#working-with-multiple-locales) for more details. ## New slug option to remove trailing slash automatically *April 11th, 2025* We’ve added a new option to automatically remove trailing slashes from slugs when the field loses focus. A trailing slash typically indicates a directory in URLs, but inconsistent use can lead to messy or duplicate links. With this update, Prepr ensures cleaner and more consistent URLs by trimming trailing slashes, helping you maintain a more structured and SEO-friendly content setup. ![remove trailing slash](https://assets-site.prepr.io/3whvnk95m6ua//slug-field-setup-highlight-new-option.png) Check out the [slug field settings](/content-modeling/field-types#slug-field) for more details. ## Introducing the new *Form* field *April 8th, 2025* With the new *Form* field, you can now easily add *HubSpot* and *Typeform* forms directly in your content items. ![content item - Form field example](https://assets-site.prepr.io/68yiyczr8ee8//contact-with-hubspot-form.png) With this feature, you keep your content and related embedded forms all in one place. Just click to search for the form you need. It's that simple. Check out the integration docs for [HubSpot](/integrations/hubspot#make-hubspot-forms-available-in-content-items) and the [Typeform](/integrations/typeform#add-form-field-to-schema) to learn how to use the [Form field](/content-modeling/field-types#form-field). ## Advanced filtering on content items *April 8th, 2025* We bring you more advanced filtering on content items to help you find exactly the content items you need. Until now, you could only filter by one value for each of the listed filter options, apart from *Tags*. With this update you can filter by multiple values, for example when you want to view a list of both *Page* and *Post* content items, you can simply choose both values when you filter by the *Model* option. ![multiple value filter example](https://assets-site.prepr.io/5gfbw3sxeqcb//advanced-filter-options.png) This update ensures efficient content searches. Check out the [content management docs](/content-management/managing-content/managing-content-items#filter-content-items) for more details on content filters. ## Help text as field value placeholder *April 7th, 2025* In addition to the help text line above a field or as a tooltip next to a field name, we've added a new way to display help texts: directly in the field value as a placeholder. Now, you can see some help text directly in the *Text*, *Slug*, *Tags*, *Number*, *Location*, and *Social* fields. ![Help text in field value example](https://assets-site.prepr.io/1i96ivrptja8//help-text-in-field-value-example.png) This gives you clear instructions while keeping the interface clean and intuitive. With this update, editor guidance is always in the right place without cluttering the design. Check out the setup details in the [field appearance settings](/content-modeling/field-types#basic-field-settings). ## New Help text field for better editor guidance *April 2nd, 2025* We're happy to bring you improved guidance while editing content with the new *Help text* field. A developer can add this field to any model or component to give you more visible and structured instructions. ![content item example](https://assets-site.prepr.io/47jck81o22wq//content-with-info-box.png) With the flexibility of this feature, it ensures smoother and more efficient content management. For more details, check out the [Help text field setup](/content-modeling/field-types#help-text-field). ## Removal of after and before parameters in REST Mutation API index requests *March 28th, 2025* We’re simplifying our REST Mutation API pagination parameters. Starting **July 1, 2025**, the following changes will take effect in all index requests: - The `after` and `before` response parameters will be removed. - The `after` request parameter (used to skip pagination items) will also be removed. If you’re currently using the `after/before` parameters, we recommend updating your integration to use the `skip` parameter instead. This update improves consistency across our APIs. ## Introducing conditional fields *March 27th, 2025* Introducing conditional fields - a huge step toward easier and more efficient content management. With conditional fields you can now choose to show or hide fields or sections depending on another field's value. ![field condition setting](https://assets-site.prepr.io/6qas0vil7869//conditional-field-setting.png) This feature simplifies the editing experience with a cleaner interface without unnecessary fields. For example, to show either the external URL field or an internal link field in the content item and not both. ![content item example](https://assets-site.prepr.io/6w0syoezj3bb//hide-conditional-field.png) Check out the [field settings doc](/content-modeling/field-types#basic-field-settings) for more details. ## New in Visual Editing: Segment & A/B Test preview *March 25th, 2025* We've enhanced [Visual Editing](/changelog#introducing-visual-editing) with new *Segment* and *A/B test* variant switches. These switches allow you to preview personalized content for specific segments and each A/B test variant before publishing the content item. By previewing content for specific groups of targeted visitors, you have more control and confidence in your content adjustments. ![new switches](https://assets-site.prepr.io/46b00z0dfkg9//content-item-detail-page-new-adaptive-switches.png) The *Segment* and *A/B test* switches are available automatically if your front end uses the [latest Prepr Next.js package](/prepr-nextjs-package). If not, check out the [setup details](/project-setup/setting-up-visual-editing#enable-segment-and-ab-test-switches) to enable the adaptive preview for any other front-end framework. ## Managing content with shortcut keys *March 17th, 2025* In line with the [*Content UX* improvements](#updated-content-item-ux) released last week, we're happy to introduce new shortcut keys to help you manage your content faster and more efficiently. Now, with just a couple of keystrokes, you can quickly select all content items with , add an item with , publish a content item with , and more - giving you greater control and saving you valuable time. For more details, check out the [managing content items docs](/content-management/managing-content/managing-content-items#manage-content-items-with-shortcut-keys). ## Improved rescheduling of content items *March 13th, 2025* Based on your feedback on the [recent Content UX updates](#updated-content-item-ux), we've improved how rescheduling works for published content — it now updates the *First Published at* date and time to the new date and time you choose when you reschedule the content item. ![rescheduling](https://downloads-site.prepr.io/1t3kx6wxot2y-rescheduling.gif) By rescheduling a published content item, you can choose how to order the content items in the front end when they're ordered by the *First Published at* date and time. This gives you more flexibility and allows you better control over the order of published content. Check out the [content management docs](/content-management/managing-content/managing-content-items#schedule-a-content-item) for more details. ## Introducing Visual Editing *March 11th, 2025* Visual Editing is finally here! This new feature allows you to view content changes to your web pages in real-time with a convenient side-by-side view in the Prepr Content page. ![Visual editing](https://assets-site.prepr.io/32z1rhexyy7m//content-item-detail-page-show-visual-editing.png) This means, you can instantly see how your edits affect the page layout and content, reducing the need to switch between tabs to check your updates. Visual Editing gives you instant, crystal-clear insight into your changes, making your editing process a lot faster, effortlessly smooth, and a great deal more intuitive. Check out the [visual editing setup](/project-setup/setting-up-visual-editing) and the [content management docs](/content-management/managing-content/managing-content-items) for more details. ## Improved UX for content references *March 11th, 2025* In response to your feedback, we've improved the UX for content references when editing a content item. ![improved UX for content references](https://assets-site.prepr.io/4ru2iq6xiixq//improved-ux-in-content-reference.png) With the updated overlays, now you always know where you are in deeply nested items. Together with a cleaner interface, this clarity minimizes errors and gives you full control over your content, making content updates seamless and stress-free. Check out the [content reference doc](/content-management/managing-content/creating-rich-content#adding-content-references) for more details. ## Updated content item UX *March 11th, 2025* To support the *Visual Editing* feature, we've updated the *Content Item* detail page with a cleaner, more intuitive interface. Primary content editing actions have been moved to the top. You'll also notice that the default publish action has been updated to match your preference. ![Content item detail page](https://assets-site.prepr.io/1ve1ys6zbd2u//content-item-detail-page.png) We trust this update gives you a more streamlined experience when editing content. Check out the [content management docs](/content-management/managing-content/managing-content-items) for more details. ## Deploying to Vercel directly from Prepr *March 10th, 2025* As you've requested, you can now deploy your website directly from Prepr. Simply click the new **Build and deploy** button to deploy your website to Vercel and the live website is updated with your latest published content as soon as you need it. ![Deploy with Vercel ](https://assets-site.prepr.io/hnk038qr1n2//vercel-deploy-drop-down.png) This new feature is especially useful for statically built and deployed websites where you don't see your content changes immediately after publishing. This way, you have more control over the website content without needing to switch over to Vercel or to contact developers to trigger a new deployment for you. Check out the [Vercel integration doc](/integrations/vercel) for the setup details. ## Improved video upload feedback *March 5th, 2025* We've improved the video upload experience in Prepr by adding a real-time progress indicator, showing the exact percentage of transcoding completion. This makes it easier to track the status of larger video uploads. Additionally, we've introduced a `Failed to Transcode` error message, providing clear feedback if an issue occurs during processing. Check out the [assets doc](/content-management/managing-assets/managing-assets#uploading-assets) for more details. ## Improved content item creation *March 3rd, 2025* Based on your feedback on adding content items, we've refined the **Add item** action for usability. Previously, when adding an item, you could select from all models when creating new content items. From now on, the model selection window excludes single-item models if their content item has been created. This update declutters the model selection, making content management more intuitive and efficient. Check out the [content management](/content-management/managing-content/managing-content-items#create-a-content-item) doc for more details. ## Setting an image focal point *February 26th, 2025* As requested, we’ve added a feature that allows you to set a focal point when adding or editing an image in a content item. ![focal point gif](https://downloads-site.prepr.io/164qz79s9dj3-setting-an-image-focal-point.gif) To enable the option to set an image focal point instead of the option to crop the image, check out the [asset field settings](/content-modeling/field-types#assets-field-settings) for more details. By setting a focal point for an image, you ensure the key parts of the image remains visible (such as a person’s face or a product), even when resized for different screen sizes. This feature means your front end delivers better visual presentation, and improves user experience. Check out the [image docs](/content-management/managing-assets/editing-and-configuring-assets#setting-an-image-focal-point) for more details. ## New Marketer role *February 24th, 2025* With the new *Marketer* role, you can add your marketing team members to Prepr. The Marketer role is designed for users who manage and optimize audience segmentation within Prepr. This role has the same permissions as the existing *Editor* role, allowing users to create, edit, and manage content. However, marketers also have access to the **Segments** feature, enabling them to define and view audience segments. Check out the [roles and permissions doc](/project-setup/managing-roles-and-permissions) for more details. ## Introducing the Zapier integration *February 19th, 2025* We set up Prepr’s Zapier integration as part of our efforts to continually improve your experience with integrating to Prepr CMS. This new integration enables automated tagging of customer profiles and provides an external trigger for event tracking in Prepr. With Zapier you can choose any listed app to send data to Prepr automatically. ![zapier](https://assets-site.prepr.io/jq5gxlf9bvq//zapier-prepr-integration.png) Think about the case where you want to add a tag with the `industry` of a known customer in Prepr when they request a demo through a HubSpot form. Previously, you had to manually export and import this data to Prepr or create a custom API integration. Now you can easily automate this process with [Zapier](https://zapier.com/apps/prepr/integrations) by simply choosing the listed app to pair such as **HubSpot**, a trigger like a **New Form Submission** (for example, when there's a demo request), and the Prepr action of **Tag a Customer Profile**. This workflow in Zapier automatically triggers Prepr to save the customer data you choose in the tag of a known customer profile. This means you have an easy, automated segmentation setup without development effort, leading to better personalization. Check out the [Zapier integrations doc](/integrations/zapier) for more details. ## Introducing support for semantic versioning (SemVer) *February 11th, 2025* As requested we've added support for semantic versioning in the *HTTP header* context in segments. This means you can create conditions like in the example image below. ![http header context with semantic versioning](https://assets-site.prepr.io/4yi9tqh949uz//http-header-context-with-semantic-versioning.png) Semantic versioning gives you more flexibility and precision with your segmentation in the HTTP header context. You can confidently enforce version requirements, preventing unwanted or inconsistent content when segmenting your customers. Check out the [segments doc](/personalization/managing-segments#http-header) for more details. ## Bulk publishing content items *February 11th, 2025* We’re very happy to bring you new options to quickly publish or unpublish multiple items simultaneously. With these new actions you can choose to publish or unpublish your chosen content items immediately or to schedule these actions for a future date. ![publish and unpublish actions](https://downloads-site.prepr.io/7901ak9umyrn-feb-11-2025-16-22-42.gif) These new features help you efficiently release and manage batches of content items, such as campaigns or updates that span several pieces of content, saving time and reducing manual effort. No more repetitive manual tasks means that you can manage your content faster, freeing up time to focus on strategy and creativity. Check out the [managing content docs](/content-management/managing-content/managing-content-items#bulk-actions-on-content-items) for more details. ## Introducing the Prepr Next.js package *February 5th, 2025* We’re excited to introduce the **Prepr Next.js package**, a powerful toolkit to streamline your personalization and A/B testing implementation. Now you can integrate Prepr’s features into your Next.js front end faster and more efficiently with the following features: - It provides API request headers for the following values: - Each visitor's customer 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 customers who enter your website through a social media campaign, for example. - HubSpot cookie, if it exists. This is useful for identifying customers who are tracked in HubSpot as a lead, for example. - The visitor's IP address. This is useful for localization. * The *Adaptive Preview Bar*. When you include this component in your front end, you allow content editors to effortlessly toggle between A/B test variants and personalized experiences for validation. ![adaptive preview bar](https://assets-site.prepr.io//21h8tyesnsiq-preview-bar-on-the-home-page.png) Check out the [Prepr Next.js package guide](/prepr-nextjs-package) or visit the [GitHub repository](https://github.com/preprio/prepr-nextjs) directly for the step-by-step instructions to install and use the package. ## Tracking customers by their email address *February 5th, 2025* You can now track a visitor's email address and store it in their customer profile in Prepr. You can do this by triggering a simple javascript in your front end when the customer provides their email address in the web app. ```js copy prepr('event', 'Email', 'jesse.ward@acme-company.com'); ``` Check out the [tracking events doc](/data-collection/recording-events#Email) for more details. This feature makes it easier to track customer interactions in other platforms you might be using, enabling more insights. ## Improved *Publication date* filter for the content item list *January 15th, 2025* We're happy to bring you an improved publication date filter when you view the content items list. The previously called *Published on* filter is now called *Publication date* for greater clarity. This filter is based on the content item *Publication date* instead of the previous *Publish on* dates. We've also updated the date selection for this filter to support future dates, allowing you to easily find not only past published content items, but also scheduled content items. ![publication date filter](https://assets-site.prepr.io/1i1w7sgk5ok5//publication-date-filter.png) For more details on filtering content items, check out the [managing content doc](/content-management/managing-content/managing-content-items#filter-content-items). ## New info text to indicate null boolean values *January 14th, 2025* We've added info text to indicate when a boolean value is null in a content item. This info text indicates that you need to explicitly set a value for this field and save the content item. ![new help text](https://assets-site.prepr.io/1o0qemomaxp8//car-content-item-empty-toggle.png) ## Sync your schema with Azure DevOps *January 13th, 2025* We're happy to announce that we've added another option to the *Schema sync* feature in Prepr. You can now choose to sync a schema using *Azure DevOps*. If your preferred tool for CI/CD workflows and source control management is *Azure DevOps*, you can include the sync process to manage schema updates in this single platform. ![sync schema modal](https://assets-site.prepr.io/10gd8h3z69ae//sync-schema-modal-azure.png) Check out the step-by-step guide in the [Azure DevOps schema sync doc](/development/working-with-cicd/syncing-a-schema#azure-devops-schema-sync). ## Support for Stories in the REST API has been fully removed *January 13th, 2025* Following the deprecation of Stories in Prepr UI in January 2024, we have now completed the removal process by eliminating all related functionality from our REST API. We trust that this update has very limited impact, if at all, but please ensure your integrations are updated, if needed. Contact Prepr support if you have any questions. ## Duplicate models, components and enumerations instantly *January 7th, 2025* We're happy to bring you yet another feature you've requested - The option to duplicate models, components, and enumerations. ![duplicate a model](https://assets-site.prepr.io/4qmw61000pdk//duplicate-a-model.png) Quickly create similar models, components or enumerations without the need to manually add each field. This saves you time and reduces errors by duplicating existing structures, streamlining your workflow for faster content modeling and delivery. For more details, check out the [content modeling docs](/content-modeling/managing-models#duplicate-a-model). ## Improved image naming and URL structure *January 6th, 2025* We're pleased to let you know that we've improved how image files are named and how their URLs are set in Prepr CMS. Now when you upload new images, they retain their original file name. The optimized URL for each image also includes a cleaner prefix after the hostname, providing a more structured and consistent format for better organization and readability. **Example** Previous URL structure: `https://example.stream.prepr.io/{format_options}/695a4d1eiaom-sustainability.png` New URL structure: `https://example.stream.prepr.io/695a4d1eiaom/{format_options}/sustainability.png` These changes make it easier for you to manage these assets, better visibility, and they align with SEO best practices. Check out the [Editing assets doc](/content-management/managing-assets/managing-assets#editing-assets) for more details on image fields. 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. ## Q4 2025 ### 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. ### Publish nested items To prevent broken or incomplete sites due to unpublished linked content, we are introducing the *Publish Nested Content Items* feature in Prepr CMS. This allows editors to publish a content item along with its related (child) items in a single action, ensuring all dependencies are live simultaneously. ### AI-generated variants for experiments With this feature you can request AI to make suggestions for A/B/n test or personalized variants to improve your experiments. This allows you to quickly and effortlessly produce diverse content for personalized experiences and A/B/n tests. ### Content trees To enhance visibility into content dependencies, we are introducing *Content Trees*. This feature provides a hierarchical tree view of specific models, allowing content marketers to easily understand and navigate content relationships. By visually mapping parent-child dependencies, editors gain better insights into how content items are structured and interconnected. ### 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. ### Redesigned role & permission management We will rework role management in Prepr to give you more granular control over content permissions. Instead of broad roles, permissions are now defined around clear actions — Create, Read, Edit, Delete, Publish, and Unpublish — with the ability to apply filters on models, locales, and workflow stages. Special permissions such as commenting, *Assigned to me* and member-based restrictions add further flexibility. ### Expanded A/B/n testing We're enhancing A/B testing to include more than two variants (A vs. B) when running these tests on specific text fields or the stack field. A/B/n testing allows you to run more effective experiments by enabling the direct comparison of multiple designs, headlines, or user flows in a single experiment. ## Q1 2026 ### 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. ### Select A/B test winner automatically Automatically select the winning variant after a predefined number of impressions or when a confidence threshold is reached. This ensures A/B tests conclude efficiently and top-performing variants are applied without manual review. ### Enhanced ‘Ask AI’ with custom and inline prompts Introduce an ‘AI Optimize’ option in Dynamic Content Fields, allowing users to refine or improve content automatically. Expand the existing ‘Ask AI’ functionality with custom prompts and inline prompting, 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. ### AI-generated image alt texts, titles and descriptions We’re introducing automated image alt text generation to simplify WCAG compliance and improve accessibility. With the new Image processing integration, Prepr can now automatically process images on upload using AI to generate titles, descriptions, and alt texts. This ensures your media library is enriched with consistent, SEO-friendly metadata — without extra manual work. 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 customer experience. 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 customer 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 customer 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. ![Recommendations-popular-items](https://assets-site.prepr.io/w_1920/a54d44b2-34a0-4396-8fe8-5d2d7644018b.jpg) 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. ![Get content item ID](https://assets-site.prepr.io/514uv9yt2crq//copy-content-item-id.png) ### 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. ![GraphQL production access token example](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) 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 You can tweak the recommendation algorithm further if you want more control over the results. Prepr uses three parameters to determine recommendations: Entities, Tags, and References. - **Entities** - Prepr uses AI Text Analysis to determine what an article is about by automatically extracting entities from the text. - **Tags** - Prepr uses the tags associated with an article. - **References** - Prepr uses an item's relationship with other content items. So in this example, Prepr looks at other articles in the same category and articles by the same author. By default, Prepr uses all three parameters to determine recommendations, but you can change that and specify the weight of each parameter. 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: 1 tags: 0 references: 0.5 } ) { items { _id title } } } ``` - We added rules: **`{ entities: 1, tags: 0, references: 0.5 }`** to indicate that tags should not be included and that references count for half. Note that the commas are optional. 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. ![Get content item ID](https://assets-site.prepr.io/514uv9yt2crq//copy-content-item-id.png) 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. ![GraphQL production access token example](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) 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. ![GraphQL production access token example](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) 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 --- # 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 customer 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 customers who enter your website through a social media campaign, for example. - HubSpot cookie, if it exists. This is useful for identifying customers 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. ![Prepr toolbar](https://assets-site.prepr.io/545864k940pz//prepr-preview-toolbar.png) - 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. 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= PREPR_ENV=preview ``` 3. To manage request headers for adaptive and A/B test content you need to implement the `createPreprMiddleware` function. Go to your `proxy.ts` or the `proxy.js` file and add the code below. If you don't have this file, you can create it in the root of your project. **Behind the scenes** - The `createPreprMiddleware` function accepts a request and optional response property and returns a `NextRequest` object. It does this so you can chain your own middleware to it. - The `createPreprMiddleware` function checks every request if the `__prepr_uid` cookie is set. If it isn't, the function generates a new UUID and sets the cookie with this new value. Then it returns a `Prepr-Customer-Id` header with the value of the `__prepr_uid` cookie to simplify your personalization and A/B testing implementation. - If the `PREPR_ENV` environment variable is set to `preview`, the `createPreprMiddleware` function also checks for searchParams `segments` and `a-b-testing` in the URL. If these searchParams are set, it sets the `Prepr-Segments` and `Prepr-AB-Testing` headers with the values of the searchParams, and stores its value in a cookie. Now that you've successfully installed the package, let's see how to use it. ## Usage ### Setting your API request headers When requesting adaptive content or A/B testing content you need to send the *Customer ID* in the request header. The `getPreprHeaders()` helper function simplifies this by setting the API request headers for you. Simply call the `getPreprHeaders()` helper function like in the example code below for a typical web page. It returns an list of headers that you can include in the request. ### Installing the Prepr preview toolbar component The Prepr preview toolbar is a small component that appears as the Prepr icon in the page of your preview website. It allows editors to quickly switch between A/B testing variants and personalization segments and to select a section of the page to open the corresponding content item directly in Prepr. The instructions below show you how to set it up. The component fetches all segments from the Prepr API. So, you need to give it access to do this as follows: 1. In your Prepr environment, click the icon and choose the **Access tokens** option to view all the access tokens. 2. Click the *GraphQL preview* access token to open it and tick the **Enable edit mode** checkbox and click the **Save** button. ![Preview access token - enable edit mode](https://assets-site.prepr.io/46aks93acmht//preview-access-token-enable-edit-mode.png) ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) Now that you've set up the access for the preview bar, you can display the Prepr preview toolbar component as follows: 1. Navigate to your root layout file, this is usually `layout.tsx`. Then add the following code to your layout file. ```ts filename="layout.tsx" import { getToolbarProps } from '@preprio/prepr-nextjs/server' import { PreprToolbar, PreprToolbarProvider } from '@preprio/prepr-nextjs/react' import '@preprio/prepr-nextjs/index.css' export default async function RootLayout({ children, }: { children: React.ReactNode }) { const isPreview = process.env.PREPR_ENV === 'preview' const toolbarProps = isPreview ? await getToolbarProps(process.env.PREPR_GRAPHQL_URL!) : null return ( {/*...*/} {isPreview && toolbarProps ? ( {children} ) : ( children )} ) } ``` Now the Prepr preview toolbar component is rendered on every page of your website. This component shows the segments in a dropdown list and a switch for A and B variants for an A/B test. By adding the `getPreprHeaders()` function to your API calls like you did in the [previous section](/prepr-nextjs-package#setting-your-api-request-headers), it automatically updates the adaptive content and A/B testing variants when you select a new segment or variant. ![preview bar - electric car segment](https://assets-site.prepr.io/po31rlv9lap//toolbar-electric-car-segment.png) ![preview bar - variant b](https://assets-site.prepr.io/3sqcdajzao8d//toolbar-b-variant-example.png) ## All done Congratulations! You've successfully simplified personalization and A/B testing, and installed the Prepr preview toolbar in your Next.js website. This brings you to the end of the setup guide for the *Prepr Next.js* package. Don't hesitate to give us feedback on your experience using this guide. ## 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/prepr-nextjs-package --- # GraphQL API The Prepr GraphQL API is a read-only API based on the GraphQL language. The GraphQL API offers more precise and flexible queries than the REST API. You can precisely define the data you want and get this data with only a single call instead of multiple REST requests. All Prepr environments have a GraphQL schema generated from associated content models. The schema is generated dynamically at request time. This ensures that changes to the schema design are instantly reflected in your web application. If you need any assistance, you're welcome to reach out to us: [Join our Slack community](https://slack.prepr.io) or [Reach out to our support team](https://prepr.io/support). Source: https://docs.prepr.io/graphql-api --- # Mutation API Reference The Prepr REST API is a Content Delivery and Mutation API. All responses are cached by our API CDN, caches will be cleared if anything changes in your Prepr environment. Contact support@prepr.io to get help implementing your application, or join our development [Slack](https://slack.prepr.io). Source: https://docs.prepr.io/mutation-api --- # Develop with Prepr Experience how easy it is to develop with Prepr CMS. Source: https://docs.prepr.io/developing-with-prepr --- # 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 --- # Step-by-step setup guide ## Introduction In this guide, you'll set up a production-ready project for a typical use case scenario where you have two environments, one for Development and one for Production. Make the most out of one of the Prepr [paid subscription plans](https://prepr.io/pricing/calculator?hutk=e939c72e0a6a2465ef3afd4d59dac5db\&is_annual=true) to create these environments. Alternatively, [sign up for a free Prepr account](https://signup.prepr.io/) to create one environment. As the owner of the account you can [manage your subscription in Prepr](/project-setup/managing-your-subscription). ## Step 1: Create environments In this step, the *Owner* creates the environments needed for the project. Check out the [Manage environments doc](/project-setup/setting-up-environments) on how to create an environment. ## Step 2: Add users Consider a simple strategy for user roles where the *Owner* makes use of the [default user roles in Prepr](/project-setup/managing-roles-and-permissions#default-roles) to create user profiles for the following types of users: - *Admin* users - For administrative users to manage environments and user profiles. Once the *Admin* user profiles have been added, these users can log in and create the rest of the users who need to have access to Prepr. - *Developer* users - For content modelers who will manage the *Schema* and developers who will manage developer settings like *Access Tokens* and *Integrations*. - *Editor* users - For content editors who will create and manage all the content. Check out the [Manage users doc](/project-setup/managing-users) for more details on how to create users and resend invitations. ## Step 3: Add roles and permissions (optional) If your users need to be grouped with a different set of permissions separate from the [default user roles available in Prepr](/project-setup/managing-roles-and-permissions), you can [add custom user roles](/project-setup/managing-roles-and-permissions#add-or-edit-roles), if your subscription plan allows. ## Step 4: Set up SSO (optional) If your project strategy for authorization includes implementing SSO (single sign-on) for users to log in to Prepr follow the [SSO setup guide](/project-setup/setting-up-sso) to complete this set up, if your subscription plan allows. ## Step 5: Migrate content (optional) If you are replacing an existing system with Prepr and have lots of important content that you want to migrate to Prepr, follow the steps in the [migration guide](/project-setup/migrating-content) to ensure a successful migration of the existing content to Prepr. ## Step 6: Integrate systems (optional) You can set up integrations between Prepr and external systems. Check out the list of [pre-built integrations](/integrations) that you can activate from within Prepr. Alternatively, for custom requirements, consider the following options for an integration solution: - Mutation API: Use the [Prepr REST API](/mutation-api) to update content items, assets, segments or customers with data from another system. - Remote source: [Set up a custom remote source](/content-modeling/creating-a-custom-remote-source) to automatically include content from an external system in your content items in Prepr. - Webhooks: [Manage webhooks](/development/best-practices/webhooks) to use events in Prepr to trigger actions such as automated notifications, deployment or data caching operations. ## What's next? Now that all the preparation steps are done, you can continue implementation in Prepr with creating a schema and the related content. Follow the [Model content docs](/content-modeling) to model content and create a schema in Prepr. When the schema is completed, follow the [content](/content-management), [asset](/content-management/managing-assets), [localization](/content-management/localizing-content) and the [collaboration](/content-management/collaboration) guides to create and manage content in Prepr. Source: https://docs.prepr.io/project-setup/step-by-step-guide --- # General overview of Prepr Before jumping into how to use Prepr, it's important to understand the high-level structure of the CMS. See the image below for a typical use case scenario where you have two environments, one for Development and one for Production. ![project structure](https://assets-site.prepr.io//6zi0eq5gzpnb-project-structure.png) As shown in the image above, Prepr is made up of the following parts: ## Organization At the top level, the *Organization* represents your company or a customer's company. An organization typically consists of one or more web applications and contains the key features below. - [Environment management](/project-setup/setting-up-environments) - Create or update environments according to your DTAP strategy. - [User management](/project-setup/managing-users) - Create or update **Users** in multiple environments and manage roles for your organization. - [Subscription management](/project-setup/managing-your-subscription) - As the *Owner* of the Prepr account, you can manage the subscription plan. - [Audit log](/project-setup/audit-log) - View user activities in each environment to help troubleshoot errors. ## Environments An *Environment* is an isolated container for your project and an organization can have one or more environments. A front-end app is usually connected to one Prepr environment. For more details, check out [the environments doc](/project-setup/setting-up-environments). Most of the setup for a typical project is done at this level including *Access tokens*, *Users*, *Locales*, *Integrations*, etc. ## Schema A *Schema* is your content structure. Check out the [introduction to a schema](/content-modeling/fundamentals) to learn more about a schema with its *Models*, *Components* and *Remote sources* and how they relate to each other. Every model, component and remote source has *Fields* defined. Learn more about fields in the [field types doc](/content-modeling/field-types). ## Content Content contains all the content items for a particular environment. This section is where content editors [manage content items](/content-management) based on the structure defined in the *Schema*, [localize content](/content-management/localizing-content) and [collaborate with other content editors](/content-management/collaboration) to publish quality content. ## Media *Media* houses all assets in the Prepr Media Library. This is where editors [manage different types of assets](/content-management/managing-assets) like images and videos for relevant content. ## Segments *Segments* allow you to group customers by common characteristics and similar behavior when they interact with your front-end apps. Use segments to set up target audiences for [personalization](/personalization/setting-up-personalization). Check out the [segments doc](/personalization/managing-segments) to learn how to set up segments and manage your customers. ## What's next? Now that you understand the high-level structure of your project, follow the [setup steps](/project-setup/step-by-step-guide) to set up your production-ready project. Source: https://docs.prepr.io/project-setup/prepr-overview --- # Architecture scenarios Discover advanced Prepr CMS features tailored for more complex project structures and organizations. Source: https://docs.prepr.io/project-setup/architecture-scenarios --- # Setting up environments *A user can belong to multiple organizations and an organization can have one or more environments. This article explains what an environment is and how to use environments in Prepr.* ## Introduction An environment is an isolated container for your project, for example for a website or an app. An environment contains the schema, content items, media files, customer segments and users. When you have multiple environments, it allows you to safely test your project without affecting your production-ready content. Let's look at how to do this in more detail. ## 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'll be prompted to add an environment. ![add environment](https://assets-site.prepr.io/ki6nbcjodkg//updated-navigation-add-new-environment.png) 2. Enter a meaningful **Name** for your environment. The **URL** will be generated automatically based on the name you entered. 3. Choose a **Default locale** for your project. Learn more about how to use locales in the [Localization guide](/content-management/localizing-content). 4. Set the **Development stage** to either *Development*, *Testing*, *Acceptance* or *Production* according to your [DTAP configuration](#set-up-a-dtap-configuration). 5. Click the **Add environment** button to confirm the settings. Next, you’ll be prompted to load Prepr demo data or start from scratch. ![Import demo data](https://assets-site.prepr.io/7gr66b3dc6wo//updated-navigation-import-demo-content.png) - **Load Acme Lease demo**. If you’re exploring Prepr we recommend loading demo data from the *Acme Lease* example. It includes examples for common use cases, like a blog and landing pages. Also, you'll get sample customer segments to try [A/B testing](/ab-testing/setting-up-ab-testing) and [Personalization](/personalization/setting-up-personalization) features in Prepr. - **Start from scratch**. If you’re setting up a Prepr environment with a specific project in mind, choose to start from scratch. This allows you to add models, components, and fields yourself. Once you've made your choice, the environment is now ready for you to use. Check out the [Users](/project-setup/managing-users) and [Roles and permissions](/project-setup/managing-roles-and-permissions) docs to manage additional users. ## Set up a DTAP configuration Many development teams use a DTAP (Development, Test, Acceptance and Production) configuration to manage their development, testing, acceptance and deployment to production. One of the first things that you need to decide before starting your project is your DTAP strategy. Your DTAP strategy will define how many environments you need to create. ## Environment setup for multiple brands Prepr offers specific features to support multiple brands in an organization. We recommend that you create an environment per brand and manage your schema and content using the following features: - Shared schema - Shared content ### Shared schema Different brands often need different content, but it makes sense for an organization to keep the structure of all the content the same across their brands. In this case, it's useful to use the same schema across multiple environments. That's what we call a shared schema. This will also simplify and speed up development by enabling a leaner and more consistent code base. To create a *Shared schema* do the following: 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 *Schema Editor*. ![shared schema](https://assets-site.prepr.io/2gn7v1d5qrsr//updated-navigation-shared-schema.png) Now you can create models, components, enumerations and remote sources that will be shared by multiple environments within your organization. Check out the [Create schema docs](/content-modeling) for more details. ### Shared content 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, enable the toggle **Allow items from all environments** when you add the [Content reference field](/content-modeling/field-types#content-reference-field) to a model. ![shared content](https://assets-site.prepr.io/4uq8gnpj6lxf//updated-navigation-shared-content.png) Check out the [Create schema docs](/content-modeling) for more details. ## Manage Environment settings You can update your environment settings by clicking the icon and choosing the **General** option. ![Environment settings](https://assets-site.prepr.io/5qjde6fn2v2//environment-settings.png) ### General settings In the *General* section, you can rename your environment, define a **Description for AI**, and change its **Timezone**, **Interface language**, and **Development stage**. #### Define environment context for AI requests If your implementation team enables any AI features, enter some context about the environment purpose in the **Description for AI** field. ![Environment settings - Description for AI](https://assets-site.prepr.io/3xwvgg0nn2mc//environment-setting-description-for-ai.png) The AI model uses this context to tailor AI requests such as those triggered by the text field *AI Generate* feature. Our AI requests use this context description to ensure outputs are consistent with the brand, audience, and overall purpose of your environment, thereby maximizing accuracy and relevance. Make use of the example below to help you define the context for your environment. ```md copy # Organization Overview: Acme Lease ## Identify the Organization - **Name:** Acme Lease - **Type:** Local business/Automotive - **Primary Language:** English ## Collect Information ### Basic Details - **Brand Name:** Acme Car Lease - **Industry:** Passenger car leasing - **Legal Name:** Acme Car Lease NL ### Operational Details - **Mission:** To provide the simplest, most transparent, and most flexible passenger car leasing experience, making it effortless to drive the perfect vehicle for their lives. - **Vision:** To be the most trusted and preferred local partner for accessible, hassle-free vehicle mobility, leading our region in the transition to smarter, more sustainable driving solutions. - **Core Values:** Trust and transparency, local focus and care, simplicity and forward mobility - **Brand:** ### Products and Services - **Main products** Passenger cars, electric passenger cars, classic passenger cars ### Geographic Presence - **Location:** Netherlands - **Operational Hours:** Daily 24 hours - **Main Distribution Channels:** Website - **Market Presence:** ### Competitive Edge and Strategy - Acme Car Lease is the most trusted, local partner for future-ready mobility. - We combine personalized, transparent service with specialized expertise in electric vehicle leasing and regional incentives that national brokers cannot match. ## Contact Information - **Phone:** +31 11 111 111 - **Email:** [hi@acmecarlease.nl](mailto: hi@acmecarlease.nl) - **Website:** [Acme Car Lease](https://acme-lease-v2.vercel.app/) - **Social Media:** - [Facebook](...) - [Instagram](...) ``` ### Content settings Apart from the general environment settings you can also manage some content-related settings defined below. #### Workflow stages You can add custom workflow stages to each of the existing Prepr workflow stages to align the collaboration workflow with your own content creation process. For example, when you have translation tasks for content items, you could add a stage like *Translate* to the *In progress* stage. ![Add custom workflow gif](https://downloads-site.prepr.io/1vkkza74owcl-custom-workflow-stages-new-nav.gif) To add a custom workflow stage, follow the steps below: 1. Click the icon and choose the *General* option. 2. Scroll down to the *Workflow stages* in the *Content* section and click the icon next to the related workflow stage. 3. Then, give your custom workflow stage a name and choose a color to represent that stage in the content pages. #### Content tree parent slug format To get the best possible result in the *Content tree* layout for your editors, you need to define the standard format of the parent content item slug values. To do this, go to the **Parent slug format** setting, and simply choose one of the values to use a predefined *Regex* expression or add a **Custom** expression. ![ parent slug format setting](https://assets-site.prepr.io/156dis0thuqy//environment-setting-parent-slug-format.png) - **Not set** - This default value means the content tree layout is not available to content editors. - **No slashes** - Choose this value if the topmost parent content items never have slashes (`/`) in the slug. - **Maximum 1 slash** - Choose this value if the topmost parent content items have no slashes or one slash. - **Maximum 2 slashes** - Choose this value if the topmost parent content items have no slashes, one slash or two slashes. - **Custom** - Create your own regex expression to match your standard format of the parent content item slug. To see the results of your definition, navigate to the *Content* page and choose the [Content tree layout](/content-management/managing-content/managing-content-items#content-tree) #### Required field validation The default drop-down value is set to **Done**, but you can choose another group of workflow stages to trigger the required field validation. For example, when a content item is moved to **Review** or **Done**. If your team implements [conditional field visibility](/content-modeling/field-types#basic-field-settings), you can also define whether Prepr needs to check required conditional fields when they are hidden with the **Ignore required fields with conditional visibility** toggle. When enabled, you allow a content item to be saved and published when a required field is hidden. #### Visual Editing visibility This dropdown allows you to choose when you can [preview content items](/project-setup/setting-up-visual-editing) directly in the content detail page. The default drop-down value is set to **To do** **In progress** **Review** **Done**. Source: https://docs.prepr.io/project-setup/setting-up-environments --- # Setting up content item previews *This article explains how to set up a preview for content items.* ## Introduction Automatically generate preview links for a content item to allow editors to preview their content directly in Prepr. This way they can review content items in a front end before they are published. ![preview in separate tab](https://assets-site.prepr.io/4wztyiybi5ku//preview-link-to-open-new-tab.png) ## Setting up preview URLs You can allow content editors to preview a content item by setting up a preview URL. You can set up preview URLs for multiple environments like production, acceptance, test, and development. Preview URLs are defined for a specific model. To add one or more preview URLs, follow the steps below. 1. Go to the **Schema** tab and choose the model you want to update. 2. Click the **Settings** button at the top of the model and click the **Preview** tab. 3. Enter a name and the preview URL construct for this model. You can use `{id}` and `{slug}` variables for your construct. Example: `https://example.com/{slug}`. ![Setting preview URLs](https://assets-site.prepr.io/3494onqrcru4//preview-url-setting-example.png) You can add an unlimited number of preview URLs to the model. The first name you set will be shown as default in the content items of this model. Check out the [Visual Editing setup guide](/project-setup/setting-up-visual-editing) for more details on the **Use in Visual Editing** checkbox. ## Showing content items that are not yet published Accessing unpublished content can be useful for previewing how a new content item will look xbefore making it available to everybody. The GraphQL API gives you control over whether you want to access published or unpublished content items in the front end. To show content items that are not yet published in the front end, use the *GraphQL Preview* access token created by Prepr during the initial environment setup. With this access token, you can retrieve content items in all available workflow stages, including *To do*, *In progress*, *Review*, *Done*, and *Published*. The content editor can then review them and make any necessary changes before publishing. ![preview access token](https://assets-site.prepr.io/6vcmqkzrxusz//preview-access-token.png) Alternatively, you can create a new access token yourself and define token permissions according to your specific needs. [Read more about GraphQL permissions](/graphql-api/authorization#permissions). ## Editing content directly with Vercel Content Link Prepr supports [*Vercel Content Link*](https://vercel.com/docs/workflow-collaboration/edit-mode). *Vercel Content Link* is a special link or URL provided by Vercel that directly serves dynamic content deployed on the platform. This feature allows content editors to edit content directly from the preview web app. When content editors open their preview web app, they can simply hover over elements to reveal a link to the corresponding item for quick updates — no developer needed. ![vercel content link in marketing site example](https://assets-site.prepr.io//256f1lmw809f-vercel-content-link-in-marketing-site.png) To enable *Vercel Content Link* for your preview environment, follow the steps below. 1. [Deploy a preview environment on Vercel](https://vercel.com/docs/deployments/preview-deployments). When deploying a preview environment, Vercel automatically generates a content link, `https://.vercel.app` for your project. 2. In Prepr, go to **Settings → Access tokens** and click the *GraphQL Preview* access token to open it. ![Preview access token - enable edit mode](https://assets-site.prepr.io/46aks93acmht//preview-access-token-enable-edit-mode.png) 3. Select the **Enable edit mode** checkbox. Once enabled, when content editors [preview the web app](/content-management/managing-content/managing-content-items#preview-content-items), they can hover over an element and click the link to open the corresponding item for quick updates. The link takes them directly to the corresponding content item in their Prepr environment. ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) Source: https://docs.prepr.io/project-setup/setting-up-previews --- # Setting up Visual Editing *This article explains how to set up visual editing for content editors to see their changes in real-time with a side-by-side view directly in Prepr CMS.* ![Visual editing](https://assets-site.prepr.io/3aosnxq8ed2i//visual-editing-example.png) ## Set up Visual Editing for web pages To set up *Visual Editing* in your Prepr environment, you need to make sure that - Inline frames (iframes) are allowed for the Prepr environment URLs. - Visual editing option is enabled for each relevant model ### Allow iframes for Prepr environments Visual editing uses iframes for this in-app preview alongside a specific content item. This means your HTTP server needs to allow iframes for the Prepr domain. If you get a server error like: `Refused to frame 'https://...' because an ancestor violates the following Content Security Policy directive...`, you can allow iframes by updating the `Content-Security-Policy` HTTP header in the web server configuration like in the code snippet below: ```cURL copy Content-Security-Policy: frame-ancestors ``` Replace `` with your own Prepr environment URLs, for example: `https://prod-acme-lease.prepr.io https://dev-acme-lease.prepr.io` where each URL is separated by a space. ### Enable Visual Editing on each model To allow content editors to use *Visual Editing* while editing content items, you first need to make sure you have the correct preview URLs set up. You can set up preview URLs for multiple environments like production, acceptance, test, and development. Preview URLs are defined for a specific model. To add one or more preview URLs, follow the steps below. 1. Go to the **Schema** tab and choose the model you want to update. 2. Click the **Settings** button at the top of the model and click the **Preview** tab. 3. Enter a name and the preview URL construct for this model. You can use `{id}` and `{slug}` variables for your construct. Example: `https://example.com/{slug}`. 4) Once your preview URLs are set up, you need to enable *Visual Editing* for the corresponding model by clicking the **Use in Visual Editing** checkbox for the applicable preview URL. ![Enable Visual editing](https://assets-site.prepr.io/7amx0ycwd28l//preview-url-setting-use-in-visual-editing-toggle.png) ![preview access token](https://assets-site.prepr.io/6vcmqkzrxusz//preview-access-token.png) ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) And that's it. Whenever a content editor edits a content item for a model with visual editing enabled, they can see their changes real-time with the side-by-side view. ### Enable *Segment* and *A/B test* switches When content editors add personalized content and or A/B test content to content items, it's useful for them to preview the content per segment and A/B variant before publishing the adaptive content. They can use the *Segment* and *A/B test* switches to do this type of live preview. You can find these switches just above the preview next to the *Screen size* icons. ![Visual editing example - adaptive preview switches](https://assets-site.prepr.io/1awkhim1vafs//visual-editing-example-variants-selectors.png) #### Next.js If you have a Next.js front end, the *Segment* and *A/B test* switches are available automatically after you [install the Prepr Next.js package](/prepr-nextjs-package) in your front end. #### Other frameworks If you're not building your front end with Next.js, you can enable the switches with the following steps: 1. Post a loaded event message like in the following code snippet: ```js copy if(window.parent !== self) { const message = { name: 'prepr_preview_bar', event: 'loaded' }; window.parent.postMessage(message, '*'); } ``` When you post this message, Prepr enables the segment and A/B test switches. 2. When an editor changes the value of the switches, Prepr adds query parameters to the URL like in the example below: ``` https://acme-lease-v2.vercel.app/?prepr_preview_ab=B&prepr_preview_segment=sgm_8ip8odwnmcc ``` The `prepr_preview_ab` parameter will have a value of `A` or `B`, while the `prepr_preview_segment` contains the `_id` value of the chosen segment. You can use these parameters to set the API header `Prepr-ABTesting` and `Prepr-Segments` to their provided values. See an example code snippet on setting API headers using Apollo. ```ts copy const { data } = await getClient().query({ query: PageDocument, variables: { slug: slug, }, context: { headers: { 'Prepr-Segments': , 'Prepr-ABTesting': }, }, }) ``` By setting these headers, your query will retrieve specific personalized content and the specific content for the A or B variant. This means the editor sees the matching personalized content for the segment they chose and the matching A/B test content for the variant they chose. ### Hide Visual Editing icon For some models, there is no need for content editors to preview content while making changes, for example, a model for the navigation bar content. For these models, you can hide the icon on the content detail page to avoid confusion. 1. Go to the **Schema** tab and choose the model you want to update. 2. Click the **Settings** button at the top of the model and click the **Features** tab. 3. Disable the **Visual Editing** toggle button. ![Visual Editing toggle](https://assets-site.prepr.io/pavclbmhwwi//model-settings-enable-visual-editing.png) ## Troubleshooting Answers to some common questions about Visual Editing. **Why do I see the "Visual Editing not available yet" screen instead of the live preview?** - This means the Visual Editing has not been enabled on the related model for this content item. To enable Visual Editing for this model, follow the steps above. **Why can't I see my content item changes in the live preview?** - This could mean the preview URL points to a production web app. If you enable Visual Editing for a production preview URL, then changes will not be visible until the user publishes the content item. Update the preview URL to one for a staging web app that uses the *GraphQL Preview* access token to see any unpublished changes in the live preview. **Why do I get the server error `Refused to frame 'https://...' because an ancestor violates the following Content Security Policy directive...`?** - This error means that iframes are not allowed for the Prepr domain. To enable them, update the Content Security Policy in your web server like in the setup steps above. **Why are the *Segment* and *A/B test* switches not visible in Visual Editing?** - If you've already installed the [Prepr Next.js package](/prepr-nextjs-package#installing-the-adaptive-preview-bar-component), reinstall it to get the latest version. If you don't have a Next.js front end, follow the [instructions](#enable-segment-and-ab-test-switches) above to activate the switches without using the Prepr Next.js package. **Why are there invisible unicode characters in the preview API response?** - These are Stega-encoded strings which produce invisible output to allow content editors to use the [Vercel **Edit Mode**](/project-setup/setting-up-previews#editing-content-directly-with-vercel-content-link). When you turn on edit mode in an access token, Stega-encoding serializes metadata into invisible UTF-8 encoded characters and appends them to string values. ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) If you have any other questions, don't hesitate to [contact our Support Team](https://prepr.io/support). Source: https://docs.prepr.io/project-setup/setting-up-visual-editing --- # Migrating content to Prepr *From this guide, you’ll learn how to prepare and migrate your content from another CMS or legacy content system to Prepr using the REST API.* ## Introduction Content migration is the process of moving content from one content management system to another. Follow the steps below to migrate content from a CMS or any other external database to a headless setup in Prepr. - [Step 1 Analyze existing content](#step-1-analyze-existing-content) - In the first step, the data analyst identifies data cleanup activities, content structure discrepancies or gaps and defines a content migration audit checklist. - [Step 2 Design mapping rules](#step-2-design-the-mapping-rules) - Based on the analysis results and the content structure in Prepr, design mapping rules to transform the content to Prepr content. - [Step 3 Create the migration script](#step-3-create-the-migration-script) - Use the mapping rules from the previous step to extract data from the legacy system and transform this data to a Prepr content structure. Use the Prepr REST API to load the transformed content into Prepr. - [Step 4 Verify and migrate content](#step-4-verify-the-migrated-content) - Use a combination of automated auditing, manual checks and system testing to confirm that the content was migrated successfully. ## Step 1: Analyze existing content It's essential for a data analyst to analyze the existing content before moving it to a new system. The results of this analysis will provide insights into necessary data cleanup activities, content structure and an audit checklist. Here is a list of key points answered during this step: - **Identify any other related external systems** - For example, where data lookups are referenced. - **Identify the set of data to be migrated** - The scope of all content that needs to be migrated can be defined with the following criteria: - **Type of content**, for example, pages, articles, authors, etc. - **Age of the content to be migrated**, for example, it might not be necessary to migrate very old or archived articles. - **The number of content items** - **Structure of content items**, i.e., what fields are included in a content item like title, slug, description, media, etc. and the corresponding validation rules, for example, whether they are mandatory or other limits. - **Technical analysis of the content items**, such as API documentation. - **Identify any necessary data rules** - **Identify the requirements for data cleansing** - Identify outdated and low-performing pages, broken links and redirects, and missing page elements such as tags, categories, meta descriptions, etc. This way, you can identify how to clean up the content and simplify the migration process. The content modeler can use the results from this analysis when modeling the new content structure for the front-end implementation. Check out the [Design schema guide](/content-modeling/fundamentals) and [UX patterns](/content-modeling/examples) for practical suggestions on designing a scalable content structure for your web app. To continue the next step for content migration, you'll need a completed Prepr schema, at least modeled if not yet in Prepr. ## Step 2: Design the mapping rules Now that you have the results of the analysis of the existing content, you can design mapping rules according to the new content structure for your web app. At a high level, look at the table below for suggestions on how to map data types from your old structure to field types in Prepr. **General field types** | Data type | Prepr field type | |-------------------------|-------------------------------| | Text entry | **[Text](/content-modeling/field-types#text-field)** | | Media files | **[Assets](/content-modeling/field-types#assets-field)** | | URL path | **[Slug](/content-modeling/field-types#slug-field)** (For a URL path to a specific content item.) | | Boolean value | **[Boolean](/content-modeling/field-types#boolean-field)** | | Predefined list | **[List](/content-modeling/field-types#list-field)** | | Integer or float | **[Number](/content-modeling/field-types#number-field)** | | Date and time | **[Date and time](/content-modeling/field-types#date-and-time-field)** | | Tags, keywords | **[Tags](/content-modeling/field-types#tags-field)** | | Coordinates | **[Location](/content-modeling/field-types#location-field)** | | Social media post embed | **[Social](/content-modeling/field-types#social-field)** | | HEX color code | **[Color](/content-modeling/field-types#color-field)** | **Special field types** Prepr supports special field types that let you create feature-rich web pages and deliver personalized content to your end users. For more details, see the table below. | Prepr field type | Capability | |-------------------------|-------------------------------| | **[Stack](/content-modeling/field-types#stack-field)** | Allows you to create a stack of components and models for feature-rich web pages. And the in-built Personalization feature lets you deliver the right content to your audiences. | | **[Dynamic content](/content-modeling/field-types#dynamic-content-field)** | Allows you to combine various elements. Those elements can include text, headings, lists and even components. This field is often used for (blog) articles that contain all kinds of elements. | | **[Remote content](/content-modeling/field-types#remote-content-field)** | Allows you to reference content in a remote source. | | **[Content reference](/content-modeling/field-types#content-reference-field)** | Allows you to create a link to another content entry. Please note each referenced content must be set up as a separate content item in Prepr.| | **[Component](/content-modeling/field-types#component-field)** | Allows adding a custom set of fields to your model. | See an example below of mapping rules of an article and the article author from a legacy CMS to Prepr. This mapping is based on the *Article* and *Person* models from the [*Blog* pattern](/content-modeling/examples/blog). You can also see the schema in a Prepr environment with Demo data or create a model and choose the *Blog* template. **Person mapping** |Legacy field| Legacy field type | Prepr field| Prepr field type |Additional rules| |------------|-------------------|-----------|-------------------|-----------------| |AUTHOR.display\_name|name|`full_name`|Text| Required | **Article mapping** |Legacy field| Legacy field type | Prepr field| Prepr field type | Additional rules| |------------|-------------------|-----------|------------------|-----------------| |headline|title|`title`| Text |Required. | |description|summary|`excerpt`| Text|Map as HTML to include styling. | |IMAGE |ImageObject |`cover`| Asset|Upload this asset in Prepr first and link with Prepr generated `id`.| |datePublished|datetime|`publish_on`| Date and time |Parse value to UNIX Timestamp.| |AUTHOR| Person|`authors`| Content reference |Create the *Person* content item first and link with Prepr generated `id`. | |body|long-text|`content`| Dynamic content|Map as HTML to include styling.| Use the JSON examples below to clarify the mapping for the content migration developer to transform and load data in Prepr with the correct hard-coded values and the matching Prepr REST API request structure. **Person JSON mapping example** ```json copy { "model": { "id": {{Prepr Person model ID in the target environment}} }, "publish_on": { "en-US": {{Current date time in UNIX Timestamp}} }, "locales": [ "en-US" // List of available languages for this content item. ], "workflow_stage": { "en-US": "Done"// The status for this content item locale entry }, "items": { "en-US": { // The locale of a specific content item entry. "full_name": { "label": "Text", // API label for a Text field "body": {{AUTHOR.display_name}} } } } } ``` **Article JSON mapping example** ```json copy { "model": { "id": {{Prepr Article model ID in the target environment}} }, "publish_on": { "en-US": {{datePublished}} }, "locales": [ "en-US" ], "workflow_stage": { "en-US": {{"Done" if datePublished is not empty, else "In progress"}} }, "items": { "en-US": { "authors": { "label": "Publication", // API label for a Content reference field "items": [ { "id": {{The auto-generated ID of the created Person}} } ] }, "content": { "label": "ElementBox", // API label for a dynamic content field "items": [ { "label": "Text", "body": {{body}} } ] }, "cover": { "label": "Asset", // API label for an Asset field "items": [ { "id": {{The auto-generated ID of the uploaded asset}} } ] }, "excerpt": { "label": "Text", "body": {{description}} }, "title": { "label": "Text", "body": {{headline}} } } } } ``` ## Step 3: Create the migration script Depending on your content migration strategy, the available legacy tools and technical solution, this process could be one or more scripts or programs to do the following: 1. Extract the content from the legacy system that matches the scope criteria defined in [Step 1](#step-1-analyze-the-legacy-content). 2. Transform the content using the mapping rules from [Step 2](#step-2-design-the-mapping-rules) and prepare it for the load process. 3. Load the transformed content using the [Prepr REST API](/mutation-api). Once you’ve transformed the content, it’s time to load it in Prepr using the Prepr REST API. Load the content in the following order: **1. Upload assets** - This is necessary if the [Prepr Media Library](/content-management/managing-assets/introduction-to-assets) will be the source repository for all the images, videos and files linked to your content. When an asset is uploaded successfully, you can then use the `id` generated by Prepr to link to it when you create the corresponding content item. Alternatively, you can include a `reference_id` on the asset for an external ID value. Check out the [REST API Manage assets doc](/mutation-api/assets-upload-update-and-destroy) for more details. **2. Create referenced content items** - If you have content that references other content items, for example, an *Article* that references an *Author*, then it's important to create the child content item first, the *Author* in this case. When the child content item is created successfully, you can then use the `id` generated by Prepr to link it to the parent content item that you will migrate afterwards. Check out the [REST API Create content items doc](/mutation-api/content-items-create-update-and-destroy#create-a-content-item) for more details. **3. Migrate remaining content items** - Once all the content dependencies have been created in Prepr, create the remaining content items using the same REST API endpoint that you used in the previous instruction. Once it's ready, run the script in a *Test* or *Development* environment to prevent affecting production-ready content. Learn more on how to [set up a DTAP configuration in Prepr](/project-setup/setting-up-environments#set-up-a-dtap-configuration). Move on to the next step to verify and migrate the content to production. ## Step 4: Verify and migrate content That’s it. The hardest part is over. After the test migration is completed, ensure all the data is moved to Prepr correctly by checking the reported totals and error logs. If you’ve already connected your front end, you can also verify the content in your web app. In case there are any inconsistencies, check and update the existing data according to the audit requirements or adjust your migration script. Once you're satisfied with the testing results, run the script in the *Production* environment. If you still have questions or need assistance, please [contact our Support team](https://prepr.io/support). Source: https://docs.prepr.io/project-setup/migrating-content --- # Managing users and profile settings *This guide shows you how to manage users in an environment or organization when you're the administrator or owner of the Prepr account. Additionally, you can learn how to manage your own account profile as a standard Prepr user.* ## Managing user accounts There are two ways to manage user accounts: on the organization level and on the environment level. A user can have other different roles in separate environments. For example, the *Admin* role in one environment and the *Editor* role in another. Check out the [Roles and permissions doc](/project-setup/managing-roles-and-permissions) for more details about *Role-based access control* for users. We recommend managing your user accounts on the organization level. ### Add users - organization level To create a user account on the organization level, complete the following steps: 1. Click the environment dropdown at the top right, choose your organization and click to open the environments overview. 2. Go to the **User management** page to open a list of all users in the environments of your organization. 3. Simply click the **Add User** button and fill in the user details. The *First name* and the *Email address* are required. 4) Choose the *Language* of this user (default English) and choose the [*User expiration date*](#define-user-expiration-date) for this user account, if needed. 5) And lastly, choose the requested *Environment* and the corresponding *Role* of this user. For more details, check out the [Managing user roles doc](/project-setup/managing-roles-and-permissions). Choose at least one role per environment. When saving a new user, an invitation email will be sent to the given email address. When saving an existing user, their account will be updated immediately with the changed permissions or roles. ![User management - selecting user role](https://assets-site.prepr.io/2gqjbh12tm4m//select-user-role-for-a-user.png) ### Add users - environment level To create a user account in the environment directly, follow the steps below. 1. Go to **Settings → Users** to open a list of all users in this environment. 2. Simply click the **Add user** button and fill in a few user details. The *First name* and *Email address* are required. 3. Choose the language of this user (default English) and the [*User expiration date*](#define-user-expiration-date) for this user account, if needed. 4. Finally, choose the *Role* for this user. See the [Managing user roles doc](/project-setup/managing-roles-and-permissions) for more details. Choose at least one role. When saving a new user, an invitation email will be sent to the given email address. When saving an existing user, their account will be updated immediately with the changed permissions or roles. ![User accounts in an environment](https://assets-site.prepr.io/6f6vx0w5mnxv//select-user-role-for-a-user.png) ### Send invitation to sign in When you create a new user and click the **Save** button, the user will receive an email with sign-in instructions. ![Email invitation](https://assets-site.prepr.io/w_1920/s3-preprmarketing/cb2cbd66-ade6-4c92-8fdf-ff97e4a517fb.png) The invitation expires after 7 days. If the recipient has an active email SPAM filter and Prepr emails end up in the SPAM box, the link expires after 12 hours. ![Account activation](https://assets-site.prepr.io//3o3nw6p7cvnf-invitation-email.png) To activate their account, they need to click the **Activate your account** button to go through the Prepr onboarding flow. This link in the email expires after 7 days. If the user forgets to accept the invitation and wants to set a password after these 7 days, they need to click the **Reset password** link on the Prepr sign-in page. ![Reset password link](https://assets-site.prepr.io/y7gjvfk2i87//reset-password.png) ### Resend the activation link to sign in Alternatively, you can resend invitations as long as the user has never signed in. A user that has not yet signed in can be recognized by the *Invited* label behind his name in the **Users** overview page. You can either choose to copy the activation link and send it directly through a messaging app or you can resend the invitation email. - To copy the activation link, hover over the user and click the icon. ![copy activation link](https://assets-site.prepr.io/22swufh8tp7//users-overview-copy-activation-link.png) - To resend the invitation email, hover over the user and click the icon. ![resend invitation](https://assets-site.prepr.io/75hf5p8il0n7//users-overview-resend-invitation.png) When the user clicks the link you've messaged them or from the invitation email, they are prompted to enter their personal details to complete the onboarding. ![Personal details](https://assets-site.prepr.io/2j9ghy2ccpx5//activate-new-account-workflow-page-1.png) Passwords must be at least 8 characters and contain at least one uppercase letter, one lowercase letter and a number. To finalize your account activation, click the **Let's go** button. You are now logged in. ![Welcome page 2 password](https://assets-site.prepr.io/3zhv4qi9sjy0//activate-new-account-workflow-page-2.png) ### Delete users When a user account is no longer needed, you can **Delete** the user if you have the permission to do so, usually as an *Admin* user or the *Owner* of the Prepr account. This can be done in one of two ways. - From the **Users** page, hover over the user you want to delete and click the icon to delete this user ![delete from user list](https://assets-site.prepr.io/4w89fwpn27ed//users-overview-resend-invitation.png) - Or click the user that you want to delete to open the the **User** detail page and click the **Delete** button. ![user delete button](https://assets-site.prepr.io/79tmtxmcfa4w//user-detail-delete-button.png) ### Agency accounts Agency accounts are user accounts of (web) agencies that take care of the implementation of your website or app. These accounts do not count toward the number of users you can add within your license. You, therefore, do not pay for agency accounts. Agency users need to use [2FA](#activate-two-factor-authentication) to sign in. [Become a Prepr partner](https://prepr.io/agencies/become-a-partner) to register your agency account in Prepr. ![Agency accounts](https://assets-site.prepr.io/7aro8hhvd3ed//users-overview-agency-label.png) ### Define user expiration date You can manage the period a user can have Prepr access. Click the icon and choose the **Users** option. Click the user that you want to manage. ![User expiration date](https://assets-site.prepr.io/4ahwaatu1qxh//user-detail-page-user-expiration-date.png) Update the **User expiration date** field on the user detail page. Select the date the account needs to expire or leave it empty to give a user lifetime access. Prepr sends a notification to the user seven days before the user account expires. One day before the expiration date, the owner of the environments gets a notification email. After this period, the user access will be revoked. When this user tries to log in, the following message is shown to this user: *Your account has expired. Contact your admin if you need access.* Any user that has a role (such as the *Owner* or *Admin* role) with the **Users** permission enabled can grant access to the expired user again. ![Expiration notification](https://assets-site.prepr.io/3wyodpu9q3ch//user-expires-notification.png) ## Managing your account profile Any Prepr user can manage their own account profile settings by clicking their avatar at the top right of the screen. ![Account profile settings](https://assets-site.prepr.io/2qi65zcecwbr//account-profile-managing-account-profile.png) ### Switch to light/dark mode You can easily switch between light and dark mode in Prepr by clicking your avatar at the top right of the screen and choosing either the **Light**, **Dark** or **System** option. ![Dark mode](https://assets-site.prepr.io/6x7tzypld7fb//account-profile-dark-mode.png) - **Light** - the standard theme with a white background. - **Dark** - uses dimmer background colors and brighter foreground colors to ensure the interface has sufficient contrast and to help reduce eye strain. - **System** - depends on your system settings (Windows, OS). ### Activate two-factor authentication Two-factor authentication (2FA) adds a second layer of login security to your Prepr account. Any user can set up 2FA individually by themselves. With 2FA enabled, you'll be asked to provide a 6-digit code after you've signed in with your login credentials. Each code is unique, and can only be used once to log in. To enable two-factor authentication, perform the following steps: 1. First, download an authenticator app, such as Google Authenticator or Authy from your mobile device. 2. Log in to Prepr and click your avatar on the top right and choose the **Profile** option to open your account profile details. 3. Then, click the *Enable two-factor authentication* toggle. ![Enable 2FA](https://assets-site.prepr.io/7593zgzm2d6c//account-profile-2fa.png) 4. Scan the QR code with your smartphone. If you can't scan the QR code you can manually enter the 6-digit verification code generated by your authenticator app. Two-factor authentication is now enabled for your account. To deactivate the 2FA, simply click the same toggle in your account profile. 5. When 2FA is enabled, the next time you log in with your email and password, you need to provide the special verification code you see in your authenticator app before you can complete the sign-in process. Each code is unique, and can only be used once to log in. ![Sign in using 2FA](https://assets-site.prepr.io/2fdmnwq7b8zn//authenticator-code-input.png) ### Add passkeys Passkeys allow you to log in to Prepr using your device's security features like a fingerprint, face scan, or PIN, instead of a traditional password. To add passkeys to your account profile, follow the steps below. 1. Log in to Prepr and click your avatar on the top right and choose the **Profile** option to open your account profile details. ![Add passkeys](https://assets-site.prepr.io/60pr7s5eygum//account-profile-passkeys.png) 2. Click the **+ Add passkey** link and choose your preferred passkey saved on your device. ![Save passkey](https://assets-site.prepr.io/l30pgbss19k//save-passkey.png) 3. Change the default name for the passkey if you'd like and click the **Save** button to save the passkey in your profile. You can then add another passkey, if needed. ![use passkeys](https://assets-site.prepr.io/497us62x3e9v//passkey-option.png) The next time you access the sign-in screen, you can then choose the **Passkey** button to log in. ### Set language preferences Go to the *Settings* in your account profile to change your personal language preferences. ![user settings](https://assets-site.prepr.io/54i0mkxhe4fa//account-profile-language-preference.png) When working in a multilingual environment, you can define your preferred language for content items. For example, if you usually work and translate content items to English, but the environment default is Dutch, you can set your **Language preference** to `en-US` for instance. For more details, check out the [localization doc](/content-management/localizing-content#working-with-multiple-locales). In addition to the language preference for content items, you can also choose between English, Dutch and French for the Prepr **Interface language**. ### Manage your personal notifications Prepr gives you the option to be notified of events in the application. This way you are always aware of events that are relevant to you. You can receive notifications via the Prepr application, via browser notifications, and via email. To activate personal notifications, you can enable notifications by following the steps below. 1. Log in to Prepr and click your avatar on the top right and choose the **Profile** option to open your account profile details. 2. Scroll down and click the **Enable notifications** toggle to choose the triggers and type of notification, via email or in the browser. ![Manage personal notifications](https://assets-site.prepr.io/pji7xk8qb3z//account-profile-notifications.png) There are three types of notifications you can receive. - Application notifications You will always see these notifications in the Prepr application. Click your avatar at the top right of the screen to see these notifications. ![notifications](https://assets-site.prepr.io/1xrn0tvnwtwl//account-profile-notification-example.png) You can then click the **Mark all as read** link to empty the notification list. - Email notifications You can also receive notifications via email. The email always contains an action button, so that you can immediately read the comment, go to the user list or check the webhook edit page. ![Email notifications](https://assets-site.prepr.io/w_1920/s3-preprmarketing/b6ad3e98-479f-468a-aa9c-7bf0f881eda6.png) - Browser notifications You can receive system notifications via your web browser. To receive browser notifications, you need to allow notifications in your browser and your Operating System. For these, make sure the **Do Not Disturb** option is disabled. ![Browser notifications](https://assets-site.prepr.io/w_1920/s3-preprmarketing/c410ae66-e020-46a7-853b-b4e3853abbdd.png) There are several events that you can choose to trigger notifications. - *When I get mentioned in a content item* You get this notification if someone mentions you when [adding a comment](/content-management/collaboration#commenting) to a content item. - *When a content item gets assigned to me* You get this notification if someone [assigns any content items](/content-management/collaboration#assignees) to you. - *When a webhook is failing* Check out the [webhooks](/development/best-practices/webhooks#response) guide for more details on webhook responses. We recommend developer users enable this notification. - *When a remote source synchronization is disabled* This notification is useful for developers who manage the integration of content items from remote sources. - *When a new user is signed in via SSO* A new Prepr user who logs in to the application for the first time using single sign-on will not yet have permissions. The owner, or another Prepr user with access to user management, must provide him with the correct permissions. You can enable this notification to check when users log in with SSO for the first time. Source: https://docs.prepr.io/project-setup/managing-users --- # Managing roles & permissions Prepr CMS uses *Role-based access control* to manage user permissions in the application. This approach makes it easy to manage access for large numbers of users. User roles can be managed by all users who have the *Organization permission* of *Roles*. To manage user roles, click the environment dropdown at the top right, choose your organization and click the icon to open the environments overview, then go to **User management** and click the **Roles** link. Here you can see a list of all roles in your organization like in the image below. ![List of roles](https://assets-site.prepr.io/691zq7k4nio7//all-roles.png) ## Default Roles We've created the default roles below which can't be edited or deleted. On top of these roles, you can create your own roles. ### Admin User with the admin role have access to everything but the billing and plan information. When added to a specific environment the admin can has access to everything within this environment, including general settings, locales, user management. When added to the organization settings, an admin can manage users from all environments of your organization. ### Editor The editor can manage, create and delete content items, and media. It can also read engagement. This role does not have functions on the organization level, but only on the environment level. ### Marketer The Marketer role is designed for users who manage and optimize audience segmentation within Prepr. This role has the same permissions as the existing Editor role, allowing users to create, edit, and manage content. However, Marketers also have access to the Segments feature, enabling them to define and view audience segments. ### Developer Developers have the same content production rights as editors, but on top of this they can create and manage webhooks and access tokens. Developers will also see API details of objects in Prepr. ### Billing Users with the Billing role have access to the organization’s plan and billing information. This includes managing payment information, viewing and handling invoices, and overseeing subscription details. ### Technical contact Users with the Technical contact role get emailed directly in the event of incidents related to failed webhooks and remote sources failing to sync. They also get an email automatically for announcements on the *Status* page. ## Add or Edit Roles On top of the default roles, you can manage your own roles. To create a role, click *Add role* and give the role a name (required). On this page, you can specify the permissions of this role. Each permission gives access to the corresponding pages. ![Add or edit roles](https://assets-site.prepr.io/71o8blee4iuz//organization-add-new-user-role.png) When creating or editing roles, please be aware of the following principles: - When you select *Default user role*, this role will automatically be added when creating a new user. - Select *Show API details* to show API details of every object in Prepr. The default role *Developer* uses this option. - When the *Content* permission is enabled, you can add the following granular permissions: - Only allow specific actions. - **Read** → This option is always enabled when you enable the *Content* permission. - **Update** → This option includes saving a content item, but not publishing it. - **Create** → You can only enable this option when **Update** is enabled. - **Delete** → You can only enable this option when **Update** is enabled. - **Commenting** → Allows users to add, delete or resolve comments. - **Publish** → You can only enable this option when **Update** is enabled. - **Unpublish** → You can only enable this option when **Update** and **Publish** is enabled. - **Bulk update** → You can only enable this option when **Update**, **Delete**, **Publish** and **Unpublish** is enabled. - Restrict permissions to specific models and locales. Leave these fields empty when the user may use all content items of all models and locales. - When you add multiple roles to a user, the most restrictive role will be applicable. For example, consider a custom *New editor* role that doesn't allow a user to delete content items. However, the default *Editor* role allows a user to delete content items. So, if you add both the *New editor* role and the *Editor* role to a user, they will not be allowed to delete content items. ## Duplicate roles When you want to use a specific role as a template for new customized roles, you can duplicate the original role. To duplicate a user role, follow the steps below. 1. Go to the **User management** tab in your organization. 2. Click the **Roles** link at the top right to open the list of roles. 3. Hover over the role you want to duplicate and click the icon to duplicate the role. ![Duplicate user role example](https://assets-site.prepr.io/6xxcsb2mklqo//user-role-list-duplicate.png) ## Owner(ship) In addition to other roles, you can manage the *Owner* role. An organization can have only one *Owner* and it has administrator rights across all environments. You can transfer ownership to another user in the organization details of your subscription. 1. Click your account profile icon and choose the **Subscription** option. 2. At the top right, click the **Organization details** link. 3. In the *Contact details* section, click the **Account owner** drop-down menu to change the owner to a different user. ![Account owner](https://assets-site.prepr.io/49irw1nfxjmi//transfer-account-ownership.png) 4. Click the **Save** button to transfer ownership. Your own role has now been set to *Admin* and you automatically lose access to the page you're on. Source: https://docs.prepr.io/project-setup/managing-roles-and-permissions --- # Setting up single sign-on (SSO) *This guide shows you how to set up integrations with Microsoft Entra ID, Google Workspace, or any identity provider using OpenID Connect or SAML 2.0 open standards to allow your users to log into Prepr using single sign-on (SSO).* ## Introduction Prepr offers several ways to log in: - Using passkeys to allow users to log in using their device pin, facial recognition or fingerprint sign-in options. - Single sign-on (SSO) is a way to authenticate and log in to an application with just one set of credentials, rather than having to set up multiple usernames and passwords across different platforms. It's a more secure process than submitting an email and password and prevents potentially losing or forgetting log-in credentials since it's stored through another service. - Submitting an email address with a password. You can integrate with [*Microsoft Entra ID (Azure)*](#microsoft-entra-id), [*Google Workspace*](#google-workspace), or any identity provider using [*SAML 2.0*](#saml-20) or [*OpenID Connect*](#openid-connect-oidc) open standards if you want to let users sign in from within your company SSO directory controlled by you or your organization. ![Integrations page - All SSO options](https://assets-site.prepr.io/72418w7wre76//all-sso-options.png) ## Microsoft Entra ID To allow Prepr users to log in using single sign-on via Microsoft Entra ID, follow the steps below to set up the integration. ## Google Workspace To allow Prepr users to log in using Google single sign-on, follow the steps below to set up the integration. ## OpenID Connect (OIDC) To allow Prepr users to log in using single sign-on via an OpenID Connect identity provider, follow the steps below to set up the integration. 1. Set up your identity provider with the following with our redirect URI details. - **Redirect Domain**: \`https://auth.prepr.io - **Redirect URI**: `https://auth.prepr.io/oidc/callback` 2. To activate the integration with your OpenID Connect identity provider, please contact [Prepr Support](https://prepr.io/support) and supply us with the following configuration data: - **Client ID** - **Client Secret** - **Issuer URL** - **Discovery endpoints** We also need the following mapping fields: - **Unique identifier** - **Email** - **First Name** (optional) - **Last Name** (optional) ## SAML 2.0 To allow Prepr users to log in using single sign-on with an SAML 2.0 identity provider, follow the steps below to set up the integration. 1. Set up the service provider (SP) config with the following details: - **SP Entity ID:** `https://auth.prepr.io/saml` - **Assertion Consumer Service (ACS) URL:** `https://auth.prepr.io/saml/acs` - Supported field mappings: `first_name`, `last_name`, `email` (The email field mapping is required.) 2. To activate the integration with your SAML 2.0 identity provider, please contact [Prepr Support](https://prepr.io/support) and supply us with the following configuration data: - **IdP Entity ID** (unique identifier of the IdP) - **SSO URL** (a.k.a. “Single Sign-On URL” or “Login URL”) - **IdP X.509 Certificate** Source: https://docs.prepr.io/project-setup/setting-up-sso --- # Managing your subscription Quickly scale up or down to support any number of users and environments. Our plans scale with your business requirements, enabling affordable trials and large enterprise implementations. Want to know more? [Explore our plans and pricing](https://prepr.io/pricing) [Contact our sales team](https://prepr.io/contact) ### Your current plan You can check your current plan on the **Subscription** page under your profile icon. If you would like to have more Users, Environments, and Records than included in your current plan, you can [upgrade your subscription](/project-setup/managing-your-subscription#change-plan) any time. ![subscription](https://assets-site.prepr.io//44xanrsqi07y-subscription-upd.png) ### User seats in your subscription A user seat means Prepr access for a user based on a personal email address. You can access Prepr with your email address on two devices simultaneously. The limit on users is a hard limit, you need to upgrade your subscription to add more users. ### Change plan If you are the account owner, you can upgrade your Community plan by following the below steps: 1. Click **Upgrade**. ![self upgrade](https://assets-site.prepr.io//z8n15umg5u6-upgrade-button.png) 2. Choose the plan that you want to upgrade to. ![choose plan](https://assets-site.prepr.io//7cb2u9khkdmi-choose-upgrade-plan.png) 3. Fill in your details and click **Upgrade**. ![upgrade form](https://assets-site.prepr.io//37tznrfjy49-upgrade-form.png) Your upgrade will be applied immediately and the invoice and usage are recalculated in real-time. To downgrade your current plan, you can contact our sales team from the **Subscription** page. Our sales team will contact the account owner about this request. ### Cancel subscription We're sorry to see you go! Please note that only the account owner can cancel the subscription. If you're sure you want to cancel, please contact our support team. Just send a message via [support.prepr.io](https://support.prepr.io/) and we will process your cancellation. ## Viewing invoices and payment details As the Owner, you can view your invoices and payment details. Only the account owner is able to access this page. You can see the amount, status and date of all invoices. ### Download Invoices If you click the title of the Invoice it will open or download a PDF-file. Here you can save it to your PC or print it. If something is incorrect on an existing invoice, you can contact billing by sending an email to [billing@prepr.io](mailto:billing@prepr.io). Please send the invoice number with your message. ### Change Payment Details To change your payment details, including your credit card and VAT numbers, billing email, click your profile icon in the top right corner, then go to **Subscription → Organization details**. Please note, your changes will only have an effect on future invoices. ![Payment details](https://assets-site.prepr.io//59z5i0mpwxb-payment-details.png) ## Monitoring data usage In the organization settings, you can have a closer look at the data usage of your environments. The usage you see is a sum of the data from all your environments. We recommend contacting support if you have any questions regarding your data usage. ### Usage #### Bandwidth The number of Gb of bandwidth used for streaming assets and API's. #### Storage The number of Gb of storage of your assets. #### Transcoding The number of minutes transcoding. 1 minute of video counts as 1, the minute ratio of audio transcoding is 4:1. ![Monitoring data usage](https://assets-site.prepr.io/w_1920/s3-preprmarketing/f3eac905-1fec-4bac-90c2-da572d56952c.png) ### Additional Data Costs All the Usage that has exceeded your plan (red text) will be charged on your next invoice. The costs of records, streaming and transcoding are described in your license and SLA. You'll only see the additional costs of the current month. For historic usage data, you can check your previous invoices. ![Additional Data Costs](https://assets-site.prepr.io/w_1920/s3-preprmarketing/599575a4-79d6-4d62-bd05-56e8b7e59705.png) Source: https://docs.prepr.io/project-setup/managing-your-subscription --- # Viewing audit log Audit logs record the occurrence of an event, the time at which it occurred, the responsible user, and the impacted entity. Audit logs are useful for developers when errors occur or if there're inconsistencies in the schema or content. ## Audit entries Every audit entry includes the user name and the date and time when the event took place. The list of entities below are tracked and listed in the audit log, if applicable. |Audit entry object | Audit entry details | |-----------------------|-------------------------------------------------------------| | **Content item** | Includes the *Title* of the content item that was created, updated, deleted or published. | | **Model** | Includes the *Name* of the model that was created, updated or deleted. | | **Component** | Includes the *Name* of the component that was created, updated or deleted. | | **Enumeration** | Includes the *Name* of the enumeration that was created, updated or deleted. | | **Remote source** | Includes the *Name* of the remote source that was created, updated or deleted. | | **Field** | Includes the *API Field Name* of the field that's created or deleted and the *Name* of the applicable model, component or remote source. |\ | **Webhook** | Includes the *Webhook ID* of the webhook that was created, updated or deleted. | | **Access token** | Includes the *Token ID* of the app that was created, updated or deleted. | | **User** | Includes the *User Name* of the user that was created, updated or deleted. | | **Asset** | Includes the *Asset ID* of the asset that was created, updated or deleted. | | **Role** | Includes the *Role Name* of the role that was created, updated or deleted. | | **Segment** | Includes the *Segment Name* of the segment that was created, updated or deleted. | | **Schema** | Includes the *Name* values of both the source and target environments that were synced for the **Sync schema** process. The **GitHub sync** process indicates if the schema was pulled or pushed. | ## Filtering the audit log View a selection of specific audit log entries with the following steps: 1. Click the environment dropdown at the top right, choose your organization and click to open the environments overview. 2. Click the *Audit log* link at the top to open a list of all audit entries in all the environments of your organization from today. 3) To filter audit entries by a specific environment, choose the environment name from the **Environment** filter dropdown. 4) To filter audit entries by a specific user, choose the user name from the **User** filter dropdown. 5) To filter audit entries by a specific audit event type like *Created content item*, choose a value from the **Event type** filter dropdown. If users perform tracked actions while you are viewing the audit log, a button will appear at the top of the list indicating the new actions and giving you the chance to refresh the list. ![audit log](https://assets-site.prepr.io//4yuhq1ztdw2j-audit-log.png) Source: https://docs.prepr.io/project-setup/audit-log --- # Set up your organization ## Managing account ownership When you first sign up for Prepr, your User account is automatically assigned the account owner role. As the account owner, you're the only one with access to subscription information, and the only one who can make updates to plan and payment settings. ### Transfer Account Ownership We know roles inside your organization can change. Therefore the current owner of the organization can transfer the ownership to another user. If you are the account owner, then you can transfer ownership as follows: 1. Click your account profile icon and choose the **Subscription** option. 2. At the top right, click the **Organization details** link. 3. In the *Contact details* section, click the **Account owner** drop-down menu to change the owner to a different user. ![Account owner](https://assets-site.prepr.io/49irw1nfxjmi//transfer-account-ownership.png) 4. Click the **Save** button to transfer ownership. Your own role has now been set to *Admin* and you automatically lose access to the page you're on. Source: https://docs.prepr.io/project-setup/organization --- # Content modeling fundamentals *This article introduces you to content modeling concepts, the importance of content modeling for developing your front end and explains how to model a robust and scalable content structure for your web app.* ## Key concepts ### Schema The schema is the content structure for your web app. It defines the organization and relationships of different types of content, the fields that can be used in the content and determines how the content is created, stored and accessed. It consists of [models](#models), [components](#components), [remote sources](#remote-sources) with their associated fields and [enumerations](#enumerations). A schema in Prepr allows content editors to efficiently add and manage content in the CMS. Before setting up your schema in Prepr, it's essential to plan and model the content in a suitable design tool. By doing this, you make sure that the schema aligns with both business requirements and the needs of the front end. ### Models A content model is a single content type that defines the structure of specific content, like a blog post, product, or event. It organizes fields, such as text, images, or links defined to store your content. ![article-model](https://assets-site.prepr.io/25oa1xqdu6id//example-article-model.png) Check out the [best practices doc](/content-modeling/best-practices#models-vs-components) on choosing models instead of components. ### Components A component is a predefined set of fields that can be used in multiple models. You can think of a component as a flexible, reusable template where you define fields once, and then fill them with different content every time you use it in a content item. Components allow for a consistent content structure across multiple models and are often used for front-end components that are not reused, like hero sections. ![SEO component](https://assets-site.prepr.io/96r0l5wfj67//example-seo-component.png) This example is a template for SEO information and can be included in different models like an article and page model. Doing this makes your schema scalable. If a new SEO field is needed, this can be done by simply adding it to the component. This means you don't have to change any of the models that embed this component. You can include this component in different types of content, such as pages or articles. Check out the [best practices doc](/content-modeling/best-practices#models-vs-components) on how to choose a component instead of a model. ### Remote sources A remote source connects third-party systems, like ecommerce platforms, to Prepr. It lets you seamlessly access and use external content, such as products or data, within your content items. You can add a remote source to your schema to define the structure of the content that is maintained in a system outside of Prepr. ![remote-content](https://assets-site.prepr.io/5zrmmdpwcdm4//example-remote-source.png) Check out the [remote source docs](/content-modeling/setting-up-a-built-in-remote-source) to learn how to set up remote sources. ### Enumerations An enumeration is a predefined list of values that can be used in models and components. When you define enumerations, you make sure that predefined, standardized values are used across content. This reduces the risk of errors or inconsistencies when content editors manage this content. For example, an enumeration for a button position might have values like `Left`, `Middle` and `Right`. Checkout the [enumerations doc](/content-modeling/managing-enumerations#add-the-enumeration-to-a-model-or-component) on how to add enumerations to a model or component. ## High level process Creating a robust schema requires thoughtful planning and collaboration. The key steps listed below help ensure your schema is efficient, scalable, and aligned with both user and business needs. By following these steps, you're creating a schema that not only meets immediate needs but also scales and adapts to future challenges. Now that you understand the basics of schema design, let's take a look at some [examples](/content-modeling/examples) to get a more concrete picture on how to design your schema. Source: https://docs.prepr.io/content-modeling/fundamentals --- # 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 --- # Content modeling best practices *This article introduces you to content modeling best practices and some tips on how to build a scalable schema for developers and ensures a smooth user experience for content editors.* ## Common challenges ### Models vs components While modeling your content, you may be in doubt about when to choose a model instead of a component and vice versa. Consider the following points when choosing a model or a component: - Models focus on what the content is, so usually you start with creating models for your main content, like pages, articles or case studies. - Models are perfect for reusable content, like categories that can be used in multiple models, like articles and case studies. - Components often focus on how the content looks, like buttons and sections of a page. - Choose components for content consistency and presentation. - Components are great for reusable structures in your front end, like page headers. In conclusion, use the general guidelines above, but keep an open mind for exceptions. ### Simple vs scalable When modeling content it's important to create a simple, yet scalable schema. A scalable schema has a flexible structure that can easily grow and adapt as your needs evolve. If you make it too simple, it might not be scalable enough and vice versa. Follow the guidelines below to find a balance between simplicity and scalability in your schema: - Start small with a minimum viable schema by focusing on essential models, fields, and relationships to support core functionality and immediate goals. - Avoid “what if” over-engineering. Add fields or relationships only when they bring real value. - Prioritize editor usability to keep their workflows simple, but leave room for refinement as needs evolve. By following these guidelines, you'll create an efficient and adaptable schema. ### Nesting models and components Nesting is structuring models or components in a hierarchy, where one model or component is embedded in another. Nesting simplifies content management by breaking down content into smaller, reusable parts. ![Nesting example](https://assets-site.prepr.io/6y6rnrebaedt//nesting.png) Nesting in content modeling is quite logical for developers because it mirrors the way content is typically structured and consumed in the front end. However, a completely flat structure makes editing very simple for content editors. So, it's important to find a middle ground when nesting models and components. Consider the following points when deciding how deeply to nest models and components: - You might choose deeply nested schemas to accurately reflect relationships. But, this can make schemas difficult for editors to manage because they need to drill down multiple levels to make basic changes, which slows workflows and increases the risk of creating errors. ![Nesting too deep](https://assets-site.prepr.io/9oiu2pswpkq//nesting-too-deep.png) - Flat schemas rely more on field conventions and references instead of nesting. This simplifies editor workflows but requires discipline in naming conventions and content structure. - Flat schemas reduce the mental load for editors and make content easier to query and scale. ### Page vs Article A page consists of modular elements so it has to be flexible for custom layouts. While an article needs to be structured for consistent formatting. In Prepr, you can enable modular page elements in the page model by using a [*Stack field*](/content-modeling/field-types#stack-field). To ensure consistent formatting in the article model, you can use the [*Dynamic content field*](/content-modeling/field-types#dynamic-content-field). The table below indicates the key differences between the two fields and essentially the structure of the *Page* and *Article* models. |Factor || | |------|------|---------| |Flexibility|Highly flexible for custom layouts.|Structured for consistent formatting.| |Editor Workflows|Editors build pages by stacking pre-configured blocks, such as image galleries and text blocks.|Editors fill in predefined fields like title, body, and tags.| |Reusability|Focus on reusing layout components across pages.|Focus on reusing content elements like tags and references.| |Optimization|A/B testing and adaptive content|-| ## Developer considerations ### Generic vs specific models and components A generic model or component is a flexible model or component, for example, a **Button** component with a styling field like `Button type` with the options, *Primary* and *Secondary*. Instead, you could opt for separate models or components to make your definition specific, for example, a **Primary button** and a **Secondary button**. There are no hard and fast rules to choose generic over specific models and components, but note the following considerations when making this decision: |Factor| Generic|Specific| |-------|--------|-------| |Flexibility|Highly flexible with many options.|Purpose-built for specific use cases.| |Ease of Use|Can overwhelm editors with too many choices.| Simpler for editors, with fewer decisions.| |Maintenance|Easier to manage one flexible model.|Multiple models may lead to duplication.| |Scalability|Scales better if options are structured well.|Becomes harder to scale with too many models.| |Front-end logic|Requires conditional logic in code.| Clearer frontend integration for developers.| ### Mapping front-end components to your schema The schema and front-end often evolve independently, leading to inconsistencies between the schema and front-end components. Misalignment can make it hard for developers to translate CMS content into front-end design efficiently. To resolve this challenge, you can align your front-end components directly to the defined models and components in your schema. ### Maintaining your schema Consider the following tips to make it easier for you to maintain your schema. - Create a modeling templates library in a repository like GitHub. This is useful when you work on multiple projects with similar requirements. For example, you could have templates for a *Page*, *Navigation*, *Article*, or *FAQ*. - Use the *Schema sync* feature in Prepr to keep your development, testing and production environments in sync. - Use clear, consistent names for models and components. - Include terms like *Grid*, *List*, *Card*, or *Carousel* to describe their purpose. - Document your naming rules to keep your team aligned. We trust that these best practices and tips can help you build a schema that meets requirements, scales and supports a smooth content editing experience. Check out the [schema fundamentals doc](/content-modeling/fundamentals) for essential concepts and considerations to get started with building your schema. If you still have questions or doubts, please feel free to [register for the Content modeling workshop](https://prepr.io/resources/content-modeling-webinar). Source: https://docs.prepr.io/content-modeling/best-practices --- # Managing models *This article explains how to create a model in Prepr, including how to manage settings and add fields.* ## Create a model Use the *Schema Editor* to create different models. You can create models from scratch, create a model using an existing template or import an model. When you create a model from scratch, you can choose to create a [*Multi-item model*](/content-modeling/managing-models#multi-item-model) or a [*Single-item model*](/content-modeling/managing-models#single-item-model). ### Multi-item model In most cases, you'll create multi-item models. These are models for which you allow content editors to create multiple content items. To create a multi-item model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Then, click the **+ Add model** link and choose the **Multi-item model** option. ![Multi-item model](https://assets-site.prepr.io/4dpmdkhj834f//muti-item-model.png) 3. Name and describe your model as follows and click **Next**. ![Model name](https://assets-site.prepr.io/3so5od5xbozx//model-name.png) |General fields | Description| |--------------------------|--------------| |*Name* |Choose a unique name for the model| |*Singular name*| This value is important for making requests with the GraphQL API. When you create a new model, this value is auto-generated as follows: PascalCase version of the model name, stripped of all non-alphanumeric characters. For example, the model name *News article* generates *NewsArticle*. |*Plural name*| This value is the same as the **Singular name**, except that the auto-generated value is the plural of the *Singular name*, for example, the model name 'News article' generates NewsArticles.| |*Description*| Fill in a description to help editors manage content by showing the purpose of this model.| |*Automatically create a shared view for this model*| Selected by default. Creates a shared view to list content items for this model. The view name is set to the plural name of the model.| 6. Choose additional features and click the **Save** button. Check out the [Manage settings](#manage-settings) section for more details. Now that your multi-item model has been created you can [add the necessary fields](#add-fields-to-a-model) to it. ### Single-item model In some cases, you want to allow the content editor to only be able to create one content item for a model, for example, to store app configuration settings such as the app name or company info. To create a single-item model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Then, click the **+ Add model** link and choose the **Single-item model** option. ![single-item model](https://assets-site.prepr.io/77xmux0iqtjb//single-item-model.png) 3. Name and describe your model as follows and click the **Next** button: ![single-item model name](https://assets-site.prepr.io/781h3ojh8s2m//single-item-model-name.png) |General fields | Description| |--------------------------|--------------| |*Name* |Choose a unique name for the model| |*Singular name*| This value is important for making requests with the GraphQL API. When you create a new model, this value is auto-generated as follows: PascalCase version of the model name, stripped of all non-alphanumeric characters. For example, the model name *News article* generates *NewsArticle*.| |*Description*| Fill in a description to help editors manage content by showing the purpose of this model.| |*Automatically create a shared view for this model*| Selected by default. Creates a shared view to list content items for this model. | 6. Choose additional features and click the **Save** button. Check out [Manage settings](/content-modeling/managing-models#manage-settings) for more details. Now that your single-item model has been created you can [add the necessary fields](#add-fields-to-a-model) to it. ## Duplicate a model In some cases you can duplicate a model to save time when you want to create a model that is similar to an existing one. To duplicate an existing model follow the steps below. 1. Go the **Schema** tab to open the *Schema Editor*. 2. Click the model you want to copy. 3. Click the button at the top of the model. ![duplicate a model](https://assets-site.prepr.io/7hjsmcgdq6fy//duplicate-model.png) 4. Choose the **Duplicate model** option. The duplicate process is an automatic export and import of the model. 5. Once done, click the **Close** button. You'll see the duplicated model in the schema with **(Copy)** in the name. You can then rename and edit the duplicated model, as needed. For example, remove fields or add new fields. ## Edit or delete a model To edit a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the model that you want to update from the list of models on the left and apply your changes. ![example-model](https://downloads-site.prepr.io/ha57p349k37-edit-a-model.gif) To delete a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the model that you want to delete from the list of models on the left. 3. Click the button at the top of the model. 4. Choose the **Delete** option. ![delete-model](https://assets-site.prepr.io/6gjtmvdaq2zq//delete-model.png) 5. Click the **Yes, delete** button to confirm the deletion. ## Manage settings To change settings for a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the model from the list of models on the left. 3. At the top of the model, click the **Settings** button to open the setting options for a model. ![model settings](https://assets-site.prepr.io/2bog3i3wmlgm//model-settings.png) Let's look at the settings in more detail. The *General* tab allows you to change the name and description of the model, if needed. ### Settings Click the *Settings* tab to restrict editors from creating multiple content items or prevent them from deleting content items. ![Model settings tab](https://assets-site.prepr.io/2848w4okglnl//model-settings-new-toggle.png) |Settings fields | Description| |--------------------------|--------------| |*Allow multiple content items* |Disable this toggle for single-item models, for example, for app configuration.| |*Allow creation from content item list*| Enabled by default. Disable this option to hide this model from the *Add item* selection list.| |*Disable deletion of content items*| Enable this toggle when you don't want content editors to delete these content items, for example, an *App configuration* content item.| ### Appearance Click the *Appearance* tab to upload a preview *Image* or to set a *Tag* for the model. ![Model settings - Appearance tab](https://assets-site.prepr.io/2v32u4bogg1b//model-appearance-settings.png) These settings help editors identify their content items more easily in stack or reference fields. The preview image helps the editor visualize the content, while the tag puts content items of this model into a logical group. ### Features Click the *Features* tab to configure the options that a content editor can see in the list of actions for the corresponding content item. ![Model feature settings](https://assets-site.prepr.io/5dzvhhc7egkm//model-settings-features.png) |Features | Description| |------------------|--------| |*Visual Editing*| This option is enabled by default. When you disable this setting, the icon will not be visible at the top of the content item page to [show Visual Editing](/content-management/managing-content/managing-content-items#visual-editing). |*Workflow*| This option is enabled by default. When you disable this setting, the *Workflow stage* and [*Assignee*](/content-management/collaboration#assignees) won't show at the top of the content item page. Disable workflow for items that don't require collaboration with other content editors such as menu items or categories.| |*Scheduling*| This option is enabled by default and allows content items to be scheduled for publishing or archiving. When you disable this setting, content editors won't see any [scheduling options](/content-management/managing-content/managing-content-items#schedule-a-content-item) in the *Publish* dropdown action list at the top of the content item page.| |*Content check*| This option is enabled by default and makes the **Content check** icon available when editing a content item. When a content editor clicks the icon, the feature automatically reviews the content item for validation issues and SEO optimization. For more details, check out the [Reviewing content guide](/content-management/reviewing-content).| |*Engagement insights*|When you enable this setting, the content editor can see and analyze metrics on content items by clicking the **Show metrics** option in the action list from the icon.| |*Commenting*|When you enable this setting, the content editor can [see and make comments](/content-management/collaboration#commenting) for the purpose of reviewing content items at the top of the content item page.| |*Versioning*| When you enable this setting, Prepr keeps track of all the changes in a content item. It allows a content editor to revert to a previous version when needed and to view the revision history. For more details, check out the [content item versions doc](/content-management/managing-content/managing-content-items#manage-versions).| #### Enable content Check To enable the *Content check* feature for content items, follow the steps below. ![Model setting - Enable Content check](https://assets-site.prepr.io/2ytter57tazu//model-settings-enable-content-check.png) 1. Open the applicable model where you want to allow content editors to use the *Content check* feature. 2. Click the **Settings** button to open the model settings. 3. Go to the **Features** tab and enable the **Content check** toggle and click the **Save** button. Now, content editors will see the action when they open a content item for this model. ### Preview Click the *Preview* tab to add URLs where content editors can preview content items. For more details on these settings, check out the [Preview content items doc](/project-setup/setting-up-previews). ![Add preview URLs](https://assets-site.prepr.io/2is37nnfu15n//model-settings-preview.png) ## Add fields to a model To add fields to your model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the model that you want to update from the list of models on the left. 3. Drag and drop the desired field type, for example, *Text*, from the list on the right into your model. ![add fields to model](https://assets-site.prepr.io/60qlp800p0bn//add-fields-to-model.png) For a complete list and all the specs, check out [Prepr field types](/content-modeling/field-types). Let's look at some basic settings that are common across all field types. 4. Using *Text* as an example, fill the *General* settings as follows: |General fields | Description| |--------------------------|--------------| |*Name*| The field label shown in the content editing interface.| |*ID*| The value of this field is automatically generated. The technical ID of this field that is used, for example, to retrieve content through the API.| For more details on the other *Text* settings, check out the [*Text field type*](/content-modeling/field-types#text-field). ## Add sections Use sections to determine the display of the fields in your content item. It allows you to organize the view of a content item for your content editors and is useful for grouping topics. For example, separate the metadata from the content such as a group of SEO fields versus article content. To add a section, follow these steps: ![Add-section](https://downloads-site.prepr.io/1fujjez7jq79-add-sections-to-model.gif) 1. Click the **Schema** tab and click to open the model from the list of models on the left. 2. Click the **+ Section** button. Fill in a name and description (optional) to save the section. 3. Drag the section above the fields that you want to group. You can also update how a section is displayed by clicking the icon in the section to edit the section settings. Click the **Appearance** tab to update some display settings: |Appearance settings | Description| |------------------|--------| |*Help text*| An instruction to help content editors. Make instructions clearer by making text **bold**, *italic*, or ***bolditalic***. Use the following standard Markdown syntax: \* or \_ (italic) \*\* or \_\_ (bold) \*\*\* or \_\_\_ (bolditalic). | |*Collapse section in content item*| Enable this value to collapse the section, by default when a content editor opens the content item.| |*Conditional visibility* -> **Show this section based on another field's value**| Enable this value if you want to make the section visible in the content item depending on another field value. You can add the following types of conditions depending on the field type: **All** - For any field type you can check if another field in the model or component is not empty or empty. **Boolean** - You can choose to match one of the boolean values. **List** - You can choose to match one or more values in the list.**Text** - You can choose to match by regex pattern, for example: Show the *Email fields* section if a text field is an email address.| ## Add columns You can also use columns to determine the display of the fields in your content item. Columns are used to divide component fields into a maximum of six columns. This is useful 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. To add columns, follow these steps: ![add-columns](https://downloads-site.prepr.io/6d2hkxhvroy8-add-columns-to-a-model.gif) 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the model from the list of models on the left. 3. Click the **+ Columns** button. 4. Drag the column element above the fields that you want divided into columns. 5. Choose the number of columns that you want those fields to be grouped into. ## View system fields System fields are system-generated and read-only fields that provide information about the content. For example, the *CreatedOn* field is the date when the content was created. Enable the **Show system fields** toggle to see the list of system fields that are available on a model. Use the *API ID* on the right of the field to query the values for these fields in your API request. Click the icon to see more information about the field. Check out the [GraphQL API reference docs](/graphql-api/schema-system-fields) for more details. ![view system fields](https://assets-site.prepr.io/6fshz9yv3quk//show-system-fields.png) ## Organize models into folders When you have dozens of models, folders make it easy to find related models. For example, when you have multiple models which are used as sections of a page. Hover over the models and click the icon. Enter a name for the new folder and choose the models that you want to include in the new folder. Click the **Add folder** button. ![Add model folder](https://assets-site.prepr.io/6thli4ytjedk//add-model-folder.png) To add or remove models from an existing folder, hover over the folder and click the icon. Choose the **Edit** option and select or deselect the models that you want to add or remove. You can also delete the folder by selecting the **Delete** option. The folder structure will be removed and the included models will return to the alphabetical list of models. ## Export and import a model Use the export and import if you only need a couple of models copied from one environment to another. For example, export a model from your staging environment and import the model into your production environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same models across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click a model from the list of models on the left. 3. Click the button at the top of the model. 4. Click **Export model** to download a JSON file of the model. ![export-model](https://assets-site.prepr.io/2e44nmmscdkq//export-model.png) To import a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Then, click the **+ Add model** button. 3. Click **Or import a model**. 4. Choose the JSON file of the model that you want to import. When you import a model, the settings are also copied across. ![import-model](https://assets-site.prepr.io/6fpo8vzl83ix//import-model.png) Source: https://docs.prepr.io/content-modeling/managing-models --- # Field types *This article contains a comprehensive list of all the field types available in Prepr.* ## List of field types |Fields | Model| Component| |--------------------------|---------|-------| |[Text](/content-modeling/field-types#text-field) For single and multi line text entry. |✓|✓| |[Assets](/content-modeling/field-types#assets-field) To add one or more assets (image, video, audio, file).|✓|✓| |[Stack](/content-modeling/field-types#stack-field) To create a stack of components and/or models often used for component-based pages. This field is where you enable the A/B testing and personalization features. |✓|✓| |[Content reference](/content-modeling/field-types#content-reference-field) To create a link to another model.|✓|✓| |[Component](/content-modeling/field-types#component-field) To add a custom **Component** to a model or another component. |✓|✓| |[Dynamic content](/content-modeling/field-types#dynamic-content-field) An advanced editor for structured elements.|✓|✓| |[Slug](/content-modeling/field-types#slug-field) To add part of a URL that describes the path to a specific content item. |✓|✗| |[Boolean](/content-modeling/field-types#boolean-field) To select one of two possible values (Yes or no, 1 or 0, true or false). |✓|✓| |[List](/content-modeling/field-types#list-field) To select an option from a predefined list.|✓|✓| |[Number](/content-modeling/field-types#number-field) To add an integer or float to your content item. |✓|✓| |[Remote content](/content-modeling/field-types#remote-content-field) To reference content in a remote source.|✓|✓| |[Form](/content-modeling/field-types#form-field) To include forms from an external source like HubSpot or Typeform.|✓|✓| |[Embed HTML](/content-modeling/field-types#embed-html-field) To add an embed to your content item. |✓|✗| |[Date and time](/content-modeling/field-types#date-and-time-field) To add a date and time to your content item.|✓|✓| |[Tags](/content-modeling/field-types#tags-field) To add a tag entry. |✓|✓| |[Location](/content-modeling/field-types#location-field) To select a location on a map or use coordinates. |✓|✓| |[Social](/content-modeling/field-types#social-field) To add a social media post to your content item.|✓|✓| |[Color](/content-modeling/field-types#color-field) To select a color or use a hex color code. |✓|✓| |[Help text](/content-modeling/field-types#help-text-field) To provide and highlight additional instructions to editors. |✓|✓| ## Basic field settings Here are some basic field settings that are common across all field types. Using the *Text* field type as an example, name the field as follows: ![basic field general settings](https://assets-site.prepr.io/65pwylwsl15y//text-field-basic-settings.png) |General options | Description| |--------------------------|--------------| |**Display name**| The field label a user sees when they edit the content item.| |**ID**| The value of this field is automatically generated. The technical ID of this field that is used, for example, to retrieve content through the API.| Click the **Appearance** tab to see the appearance options for the field. ![Text field appearance settings](https://assets-site.prepr.io/4zwhz9jfejo2//text-field-appearance-settings.png) |Appearance settings | Checkbox or radio button options | Description| |------------------|--------|--------| |**Help text**| - **Show help text above field** - **Show help text in tooltip next to field name** - **Show help text inside the field**|An instruction to help content editors. Make instructions clearer by making text **bold**, *italic*, or ***bolditalic***. Use the following standard Markdown syntax: \* or \_ (italic) \*\* or \_\_ (bold) \*\*\* or \_\_\_ (bolditalic). You can choose to either display the help text just above the field, as a tooltip next to the field name, a content editor can see when they hover over the icon, or directly in the field value as a placeholder.| |**Conditional visibility** | **Show field based on another field's value**| Enable this value if you want to make this field visible in the content item depending on another field value. You can add the following types of conditions depending on the field type: **All** - For any field type you can check if another field in the model or component is not empty or empty. **Boolean** - You can choose to match one of the boolean values. **List** - You can choose to match one or more values in the list, for example: Show *Model year* when the *Product type* is `Car`.**Text** - You can choose to match by regex pattern, for example: Show *Subject* field if field is an email address.| |**Field display** |**Default** | The default UI setting. This option allows the field to be edited by any user in the UI.| |**Field display** | **Read only**| Disables the field in the UI and it can only be edited through the API.| |**Field display** | **Hidden for non developers**|The field is only visible in the UI for users with developer permissions.| Click the **Validation** tab to see the validation rules for the field. ![Basic validation setting - Boolean example](https://assets-site.prepr.io/41njwih0cu2w//basic-field-validation-boolean-example.png) Enable **This field is required** if this is a mandatory field. The validation only triggers when a content item is set to the *Required field validation stage* defined in the [environment settings](/project-setup/setting-up-environments#manage-environment-settings), usually the **Done** workflow stage. For more details, check out the [Workflow stages doc](/content-management/collaboration). ## Text field The text field allows content editors to add single and multi-line text elements to your content item. Click the **Settings** tab to fill in the following settings: ![Text settings](https://assets-site.prepr.io/2qvc3cnynrra//text-field-settings-improved-inital-value-selection.png) |Settings | Description| |--------------------------|--------------| |**Single line** |Allows only one text line to be entered| |**Text area**| Multiple text lines without layout options| |**HTML editor**|Multiple text lines with layout options, like heading, bold, italic, underlined, list, dynamic and external links, table, and alignment.| |**Initial value**| You can enter a fixed value or choose a field to prefill this value automatically while a content editor creates or edits the content item. The value can be overwritten manually. For a dynamic initial value, simply click the corresponding API name from the list of fields in the info box. The list of fields includes the system fields `id`, `user.full_name`, `user.first_name`, `user.last_name` and any other *Text* field, Content reference field, like `categories.title` or List field.| If you choose the *HTML editor* text field, then you can also enable/disable **Heading** options in the settings: ![HTML Text field display options](https://assets-site.prepr.io/61r7z50oxnwq//html-text-settings.png) Enable the **Heading** option to allow headings and choose which of the headings (1 - 6) will be available to content editors. When you create a new Text field and enter a fixed **Initial value** (instead of choosing a dynamic value from the list) and content items already exist for the model, a confirmation modal appears. Click the **Yes, apply,** button in the modal to automatically update all linked content items with this value. ![Fixed initial value - confirmation modal](https://assets-site.prepr.io/4d1tz5ewh67u//fixed-initial-value-update-existing-content-items-modal.png) For details on **Appearance** options, check out [the basic field settings](/content-modeling/field-types#basic-field-settings). Click the **Validation tab** to set up validation rules: ![Text field validation settings](https://assets-site.prepr.io/3055dctxx67//text-field-validation-settings.png) |Validation | Description| |--------------------------|--------------| |**This field is required** |Prevents saving a content item if this field is empty| |**This field must be unique** |Prevents saving a content item if this field value already exists for this field in another content item. This validation can only be enabled for a *Single line* type for a text field.| |**Allow scripts**| Make it possible to copy-paste or add (HTML-)code in a content item| |**Limit character count**| Specifies a maximum allowed number of characters. This option is useful, for example in titles when your website or app accepts a limited number of characters| |**Match a specific pattern**|Only accepts specified regular expression (regex). Validates that the value of a field matches a specific pattern defined by a regular expression. For your convenience, you can choose from a number of common predefined regex rules: - **Email**: An email consists of a user name, followed by ‘@’ followed by a domain name. Characters allowed in a user name are alphanumeric characters (a-z, 0-9), ‘\_’, ‘.’, ‘-’. - **URL**: A valid URL requires a protocol prefix (http, https) and a top-level domain, like - `domain.com` - `www.domain.com` - `http://domain.com` - `https://domain.com` - `https://www.domain.com` - **Date (European)**: Dates in the format ‘DD/MM/YYYY’. Single-digit months and days may or may not have a leading zero. You can use / and - and . as digit-dividers: - d.m.yyyy - dd.mm.yyyy - d/m/yyyy - dd/mm/yyyy - d-m-yyyy - dd-mm-yyyy - **Date (US)**: Dates in the format: - m.d.yyyy - mm.dd.yyyy - m/d/yyyy - mm/dd/yyyy - m-d-yyyy - mm-dd-yyyy - **12h Time**: Accepts time values in the HH:MM:SS AM/PM format. Allowed hours are from 01 to 12, columns are required, while the use of seconds is optional. The input must contain AM/PM notation in either lower- or upper-case: - hh:mm AM - hh:mm:ss AM - hh:mm PM - hh:mm:ss PM - **24h Time**: Accepts time values with format HH:MM:SS. Allowed hours are from 01 to 24. The input cannot contain AM/PM notation: - hh:mm - hh:mm:ss Please note that predefined regex rules don't work on HTML editor text fields. To make a regex work on a HTML editor, you need to add a custom regex, like `^(?:<(.*)>car(?:<\/\g{1}))$` (instead of `^car`). ### Item title and SEO fields By default, the first text element in your model or component is used as a title. This label is used to display the item in lists. You can manually change the title to another text element by clicking the icon and choosing the action for that field. You can also mark a field as an **SEO title** or **Meta description**. ![item title](https://downloads-site.prepr.io/uqxkbuarwk1-set-seo-title.gif) The text field labels in the model overwrite the text field labels in a component used in the same content item. For example: If the title in a *Page* is set as the `SEO title` and the page content item includes a *Header* component with a text field that is also set as an `SEO title`, then the model text field will be used as the SEO title for the page content item. ### AI Translate The [*AI Translate*](/content-management/localizing-content#create-a-language-variant) feature automatically creates high-quality first drafts of content items in a chosen language. This feature lightens the workload for content editors who need to create translated copies of a content item. The *AI Translate* feature is enabled by default for all models and all text fields. To disable the *AI Translate* feature for specific fields, follow the steps below. ![Disable AI Translate](https://downloads-site.prepr.io/6li1716u5k8o-disable-translate-specific-field.gif) 1. For the field that shouldn't be translated, click to open the **AI** tab. 2. Disable 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. ### AI Generate The *AI Generate* feature generates new text on request, for example, when a content editor wants 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 the *AI Generate* feature for specific fields, follow the steps below. ![Enable AI Generate example](https://downloads-site.prepr.io/7g8yekttl9l1-9qfrflyogmt1aj7ob95y5cujcndkfbfyedzx9omfgif.gif) 1. Click to open the **AI** tab. 2. Enable the **Allow AI text generation** toggle. 3. To set the prompt, it's easiest to choose one of the suggested prompts and adjust it for your own needs. ### AI Optimize The *AI Optimize* feature helps content editors 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 the *AI Optimize* feature for specific fields, follow the steps below. ![Enable AI Optimize settings](https://downloads-site.prepr.io/52kf8ak0igos-enable-ai-optimize.gif) 1. Click the field that can be optimized, and open 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 Now, content editors will see the **Ask AI** action when hovering over the enabled field. ### A/B testing Click the **A/B testing** tab to enable or disable the A/B testing. When it's enabled, you allow content editors to add A/B testing variants to a text field. ![Enable A/B testing](https://assets-site.prepr.io/1gccry3ru4lm//text-field-ab-testing-setting.png) ## Assets field Prepr supports multiple asset types: images, files, videos, and audio files. For more details on how to work with assets, check out the [Work with assets guide](/content-management/managing-assets). When adding a new assets field to a model/component, you can choose between a Multiple-asset field or a Single-asset field depending on the number of assets you want to add. The chosen type can be changed later in the field configuration. ![Multiple-asset and single-asset field](https://assets-site.prepr.io//79t4r4ic86nc-assets-field-type.png) From the **General** tab, select which **Asset type** is allowed in this field, such as image, video, audio, or file. Here, you can also change the **Field type** you've chosen previously, from multi-asset to single-asset, and vice versa. ![assets-field](https://assets-site.prepr.io//7in531hceco8-assets-general-tab.png) ### Assets field settings Click the **Settings** tab to choose the following settings for an *Assets* field: ![assets-settings](https://assets-site.prepr.io/20jwlfhkw8wh//asset-field-settings-all.png) | | Description| |--------------------------|--------------| |**Set as multi-asset field**| Enabled by default. This option allows content editors to add more than one asset to their content item for this field. Disable this option if you want to restrict the field to one asset only, such as the cover image for a blog post.| |**Allow alignment**|Enable this option to allow the content editor to left-, center- or right-align the asset.| |**Allow caption**|Enable this option to allow the content editor to provide a caption for the asset.| |**Set image focal point**|Enabled by default. This option allows content editors to set a focal point in the image.| |**Focal point is required**|This setting is visible when you enable **Set image focal point**. Enable this option to make it mandatory for the content editor to set an image focal point.| |**Set image presets**| Enable this option for content editors to crop images. When enabled, you can define multiple presets for cropping. The *Image presets* are image size (aspect ratio) templates you can define for different device types or use cases. For example, you may want to define a preset for displaying images on mobile or using them in a banner. Note that crop values are not based on image resolution.| |**Cropping is required**| This setting is visible when you enable **Set image presets**. Enable this option to make it mandatory for the content editor to crop the image.| For more details on how to resize assets in the API, check out the [GraphQL field types doc](/graphql-api/schema-field-types#assets) and the [REST API docs](/mutation-api/assets-resizing). For more details on how to use the image options, check out Edit and configure assets [Edit and configure assets](/content-management/managing-assets/editing-and-configuring-assets). Click the **Validation** tab to indicate if this field is required. ![assets-validation](https://assets-site.prepr.io/w_1920/1qvzqjxwdxnb-screenshot-2022-09-27-at-191445.png) For the multi-asset field type, you can also enable the Limit input option and set a minimum and a maximum number of assets allowed. ## Stack field The **Stack** field allows content editors to 'stack' multiple components and content items within a single field. It also allows them to personalize elements in a stack. Check out the [Personalization](/personalization/setting-up-personalization) guide for more details. The stack field is often used to structure the elements for web pages. When you add a stack field to a model or component, you can choose to create a single stack. For example: if a page content item can only have one header. The chosen type can be changed later in the field configuration. ![new-stack-field](https://assets-site.prepr.io/2vapwlssaxg1//stack-field-modal-general.png) Define the general options as follows: |General options | Description| |--------------------------|--------------| |**Allowed models and components** | Select all the models and components that the content editor can include in this stack. | |**Allow new items to be created**| For each model, disable this option if the content editor should only reference existing items while compiling the stack. | |**Allow items from all environments**| For each selected model, enable this option to allow content editors to include content items for this model from other environments within the organization. This allows the content to be shared across an organization. For more details on shared content, check out the [Environments doc](/project-setup/setting-up-environments#shared-content).| Click the **Settings** tab to define the settings below. ![stack field settings](https://assets-site.prepr.io/2xystt447k3i//stack-field-modal-settings.png) | Settings | Description| |--------------------------|--------------| |**Allow multiple content references and components**|Disable this option to limit the content editor to adding a single referenced item or a single component in the stack of the model or component. | |**Initial value**|You can set an initial value to a list of existing content items and components to help content editors create a content item more quickly.| Click the **Validation** tab to enable the **Limit input**. Enable this option to set a minimum and maximum allowed number of referenced content items and components. ![stack-field-validation](https://assets-site.prepr.io//rab16anq5rw-stack-field-settings-validation.png) Click the **A/B testing** tab to enable or disable the A/B testing. If you disable it, this feature will not be available to content editors to add A/B testing groups to this stack field. ![Enable A/B testing](https://assets-site.prepr.io//7a3tpi1fmza1-stack-field-settings-ab-testing.png) Click the **Adaptive content** tab to enable or disable the *Adaptive content* feature. If you disable it, content editors will not be able to personalize elements in this stack field. ![Enable adaptive content](https://assets-site.prepr.io//3z3qgsle6e7x-stack-field-settings-adaptive-content.png) Check out the [Example Page pattern](/content-modeling/examples/page) doc for details on how to use the stack field in your model or component. ## Content reference field The content reference field allows content editors to make a reference link from one content item to another. When you add a content reference field to a model or component, you can choose to create a single content reference. The chosen type can be changed later in the field configuration. From the **General** tab, select the following options: ![general](https://assets-site.prepr.io/41s89yg9tkf6//content-reference-modal-general.png) Select the models and complete the general options as follows: |General options | Description| |--------------------------|--------------| |**Allowed models** |Select all the models that the content editor can use within the content reference field.| |**Allow new items to be created**| For each model, disable this option if the content editor should only reference existing items.| Click the **Settings** tab to view the following settings: ![content reference settings](https://assets-site.prepr.io/67pqtmmyv8m2//content-reference-modal-settings.png) | Settings | Description| |--------------------------|--------------| |**Allow multiple content references**|Disable this option to limit the content editor to adding a single referenced item to the model or component. | |**Initial value**|You can set an initial value to an existing content item that prefills the value when a content editor creates a content item.| Click the **Appearance** tab to set the type that determines how the field is displayed on the content item. ![appearance](https://assets-site.prepr.io//joppu4ae7fi-dynamic-content-field-appearance-tab.png) Choose to show a link field as a *Modal with search*, an *Autosuggest dropdown*, or as *Checkboxes*. Click the **Validation** tab to enable the **Limit input**. Enable this option to set a minimum and maximum allowed number of referenced content items. ![validation](https://assets-site.prepr.io//19etfkm1v72h-content-reference-validation.png) ## Component field The **Component** field allows content editors to include the predefined fields from a previously created [component](/content-modeling/managing-components). From the **General** tab, choose the component that you want this model to use. ![Component-field](https://assets-site.prepr.io/w_1920/3o7yfyb2j5ur-component-field.jpg) Go to the **Appearance** tab, to choose the display options. ![component settings modal](https://assets-site.prepr.io//66knm8w20tsq-component-settings-modal.png) |Appearance options | Description| |--------------------------|--------------| |**Display fields as a group** |Enabled by default to display the component fields in a group with a title separated from other fields in the content item. When this toggle is disabled, component fields are displayed like any other content item field. | ## Dynamic content field The dynamic content field allows content editors to combine various elements. Those elements can include text, headings, lists and even components. The dynamic content field is commonly used to create articles with a variety of content and different styling for each element. This field offers different elements, with variable options that you can manage in the model: Click the **Content types** tab to enable the following elements: ![Dynamic content content types](https://assets-site.prepr.io//6uytezna5c3h-screenshot-2022-09-12-at-130512.png) ![Dynamic content content types 2](https://assets-site.prepr.io//3ff7hfq0q0aw-screenshot-2022-09-12-at-134554.png) |Settings | Description| |--------------------------|--------------| |**Heading** |Enable to allow headings and choose heading 1 - 6.| |**Paragraph**| **Allow layout** - Enable this option and choose from eight formatting options. **Allow scripts** - Make it possible to copy-paste or add (HTML-)code in a content item. |**Assets**|Enable to allow assets, then choose types of assets and formatting options.| |**Social**|Enable to allow one or more of the major social platforms.| |**Other**|Enable to include location.| |**Remote sources and forms**|Enable to allow editors to include remote content or forms in content items. This option is available when at least one [remote source](/content-modeling/setting-up-a-built-in-remote-source) or form integration like [HubSpot](/integrations/hubspot) or [Typeform](/integrations/typeform) is set up in Prepr.| |**Components**|Enable to choose previously created [components](/content-modeling/managing-components). A list of components are made available to choose from when this option is enabled.| ## Slug field A slug is part of a URL that describes the path to the specific content item. It is the part that comes after your domain name in the URL. You can only add one slug field per model. Fill in the **Settings** tab as follows: ![slug-settings](https://assets-site.prepr.io/5mdhz79lu20f//example-slug-field-settings.png) |Settings | Description| |--------------------------|--------------| |**Slug template**| This value is used to auto-generate a slug value when a content editor creates a new content item or clicks the regenerate icon. Construct the template by clicking the corresponding API name from the list of fields in the info box. The list of fields includes the system fields `id`, `locale`, `country`, `lang`. The list of fields also include any other *Text* field, for example: `name` and `excerpt`, *Content reference* field, for example: `categories.id` and `categories.slug`, *Remote content* field, for example `e_commerce_product.name`, or *List* field as defined in the model. | |**Automatically generate unique slugs**| When a new content item is created with a slug value that already exists, Prepr auto-generates a unique slug in the format **provided slug template** + **'-'** + **#**, where **#** is an incremented number, for example, news-article-1 or news-article-2. When this setting is disabled, no unique slug will be generated, but an error will occur to indicate a duplicate content item.| |**Remove trailing slash**| This option ensures that slugs never end with a forward slash. If a trailing slash is added manually, it will be automatically removed when the slug field loses focus. This helps maintain clean, consistent URLs across your content.| |**Make slug prefix read-only**|When enabled, editors can only modify the part of the slug that comes after the last slash. In other words, the first part of the slug becomes read-only. When this option is disabled, editors can modify the whole slug value.| For an example on how to use the slug field, check out the [preview URL setup guide](/project-setup/setting-up-previews#setting-up-preview-urls). ## Boolean field This field allows content editors to choose one of two possible values. You can define these values in the **Appearance** tab. ![Boolean field](https://assets-site.prepr.io//haaj3z1fe21-boolean-appearance-settings.png) |Appearance | Description| |--------------------------|--------------| |**True condition label** |Specify a label for a true value| |**False condition label** |Specify a label for a false value| In the **Settings**, you can choose the **Default value**. When the content item is created, this value will be set automatically and a content editor can overwrite it, if needed. ![boolean initial value](https://assets-site.prepr.io//32z4yby1sqyv-boolean-settings.png) If content items already exist for the model, a confirmation modal appears when you save the field. ![boolean confirmation modal](https://assets-site.prepr.io//1f6r4zw3nov9-boolean-field-default-value.png) Click the **Yes, apply,** button in the modal to automatically update all linked content items with the **Default value**. ## List field The list field allows content editors to make a choice out of the given options. From the **General** tab, fill the list items with key-value pairs. A key-value pair allows you to set up a list item with a technical name (a unique identifier, a key) and a user-friendly value that you see in the content items (the data, the value). ![list field](https://assets-site.prepr.io/w_1920/7i4xbb7bwgsu-list-field.jpg) Click the **Settings** tab to set an **Initial value**. The value entered here is automatically prefilled on the content item, but content editors can overwrite this value manually. ![list initial value](https://assets-site.prepr.io/w_1920/s3-preprmarketing/cbd4e03c-3c48-4f0b-a90e-e2c163cb16b2.png) When you enter an **Initial value** and content items already exist for the model, a confirmation modal appears. Click the **Yes, apply,** button in the modal to automatically update all linked content items with this value. ## Number field The number field can be useful when you want to add numerical data to your content item. For example year of birth, stock number, or product prize. The Integer and Float fields can hold 32-bit safe values. From the **General** tab, you can choose the **Number type**: **Integer** or **Float**. ![Number field](https://assets-site.prepr.io/w_1920/2ebziuqaudxr-number-field.jpg) Click the **Settings** tab to set an **Initial value**. The value entered here is automatically prefilled on the content item, but content editors can overwrite this value manually. ![Number settings](https://assets-site.prepr.io/w_1920/3ryn8s5l7wfg-number-field-settings.jpg) When you enter an **Initial value** and content items already exist for the model, a confirmation modal appears. Click the **Yes, apply,** button in the modal to automatically update all linked content items with this value. Click the **Validation** tab to enable validation rules. |Validation | Description| |--------------------------|--------------| |**This field is required** |Prevents saving a content item if this field is empty.| |**This field must be unique** |Prevents saving a content item if this field value already exists for this field in another content item.| |**Limit input**| Enable this option to set a minimum and maximum allowed value.| ## Remote content field The **Remote content** field allows editors to use content maintained in an external system in content items. On the **General** tab, name the field and choose the desired remote source. For more details, see the available [integrations](/integrations). ![Remote content field](https://assets-site.prepr.io/w_1920/3zv4lpq34935-remote-content-field.png) ## Form field The **Form** field allows editors to include forms from an external system like *HubSpot* or *Typeform* in content items. On the **General** tab, name the field and choose the platform where the form comes from. ![Form field](https://assets-site.prepr.io/op274d9ddj5//hubspot-form-field-example.png) For other options, check out the [basic field settings](#basic-field-settings). ## Embed HTML field You can easily use Prepr content on your front-end with the embed field. This kind of embedded code is short code, usually in HTML language for users to copy and paste into a website. This is useful when you want to include content in Prepr in another website. Click the **Settings** tab and enter the default embedded HTML, such as iFrame code. Choose variables (embed fields) to add data dynamically from other fields. ![embed html settings](https://assets-site.prepr.io/w_1920/6pcjj3qap6f6-screenshot-2022-09-12-at-172229.png) ### Using plain text or HTML encoded variables By default, you can pre-fill the title and ID of the content item, but you can also choose to add other fields to your embed structure. You can only use API IDs of fields that you have added to your model. Each text field will generate a plain text variable as well as an encoded variable. When using embed codes, it can be necessary to use encoded URLs, so that specific characters are encoded to an HTML structure (f.e.: spaces are encoded into %20 characters). To use an encoded variable, click the **.encoded** field to add. ![embed html](https://downloads-site.prepr.io/2e86f81a-a13e-4895-b8ab-a37ad0e4d677.gif) ### Building the embed code Once you have added the embed HTML to your model, you will see this field in all content items of this model. All variables (API IDs) are replaced in real-time with the data you enter in your content item. ### Plain text embed ![plain text embed](https://assets-site.prepr.io/w_1920/s3-preprmarketing/4fa3341f-4f30-4b13-8ee5-21cc2ed4d3ed.png) ### Encoded embed ![encoded embed](https://assets-site.prepr.io/w_1920/s3-preprmarketing/914909f4-7b84-43fd-a477-2ccd056dd355.png) ### Using the embed code To use the embed code on your front-end or a third-party website, simply click ' Copy code' to save the embed code to your clipboard. ## Date and time field The field Date and time allows content editors to add dates and times to your content items. From the **General** tab, choose a **Type** as follows: - **Date** - A date-only field - **Date range** - A start date and end date - **Business hours** - A day and time picker to enter AM and PM openings hours. ![date-and-time](https://assets-site.prepr.io/w_1920/9vlp6q17fnz-date-and-time-field.jpg) Click the **Settings** tab and fill the settings as follows: |Settings | Description| |--------------------------|--------------| |**Allow time selection (hh:mm)**| Enable this option to add a time to your date or date range. | |**Allow extra dates**|Enable this option to use multiple date or date ranges.| ![date-and-time-settings](https://assets-site.prepr.io/w_1920/78lu5al1bkzy-date-and-time-settings.jpg) ## Tags field This field allows content editors to add tags to your content item. In the **Appearance** settings, choose one of the follow **Type** values: - **Free tag entry** - **Restrict entry to tag group** - For the **Restrict entry to tag group** option, choose a predefined tag group and choose either **Checkboxes / Radiobuttons** or **Autosuggest** ![Tags settings](https://assets-site.prepr.io/w_1920/6fxzrvl5gbmb-screenshot-2022-09-12-at-180101.png) If you have the SEO score option selected in a model, tag suggestions will be visible as the **Free tag entry** field. For example: ![suggestions](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8d301eb9-6fae-4ce4-966c-cce704bdc895.png) ## Location field The field Location allows content editors to add Google Maps geo-points (coordinates or an address) to your content item. See the [Basic field settings](/content-modeling/field-types#basic-field-settings) on how to add a *Location* field to a model. Check out [Adding elements to a content field](/content-management/managing-content/creating-rich-content) for an example on how location content is added. ## Social field Prepr supports several social embeddings. You can select one of them for each social field. In a content item, editors can copy and paste a social URL. Prepr will generate a preview of the social post. From the **General** tab, select the type as follows: ![social](https://assets-site.prepr.io//4r6jc3cidudr-social-field.png) ## Color field The color field allows content editors to choose a color. For example, this is useful when you want to manage your front-end styling in Prepr. Click the **Settings** tab to set an initial value. This means that the value is prefilled on the content item automatically. This value can be overwritten manually. ![color initial value](https://assets-site.prepr.io/w_1920/28m4984mzv7o-screenshot-2022-09-19-at-163721.png) ## Help text field Unlike other fields, the help text field is not an entry in a content item. This field is a definition of how to display any additional guidance instructions in a content item. ![Help text field setup](https://assets-site.prepr.io/1s4oofsi1j9e//help-text-field-general-tab.png) When you add a help text field, simply set a *Title* that appears in bold at the top of an information box. Add your instructions or help text in the *Description* value. You can use standard Markdown to highlight key instructions. ![Help text field appearance](https://assets-site.prepr.io/1fx8nwu2htj6//help-text-field-appearance-settings.png) Go to the **Appearance** tab to set the **Background style**. You can customize the background color by choosing *Default* (light gray) *Info* (blue) or *Warning* (yellow) to highlight appropriate guidance. Check out the [basic settings](/content-modeling/field-types#basic-field-settings) for details on how to set up the **Conditional visibility**. The instructions will appear in a highlighted box in the position you add the field in the model or component. In the example below, the field was added as the first field in the *SEO* component. ![content item example](https://assets-site.prepr.io/47jck81o22wq//content-with-info-box.png) Source: https://docs.prepr.io/content-modeling/field-types --- # Defining the Asset model *This article explains how to set up the asset model in Prepr to add fields to assets and to enable localization.* ## Introduction The Asset model is a model that's part of the Prepr *Schema* and [*Shared schema*](/project-setup/architecture-scenarios/shared-schema) by default and cannot be deleted. The Asset model allows you to define additional fields and to enable localization for all assets. ## Asset fields The fields listed below are the core fields always available in an asset. These fields are also used for internal purposes, for example: in thumbnails, media browser, for Alt text, etc. - *Internal name* - This field is required and is used to enter the *Title* of the asset. - *Author* - This optional field can be used to enter the name of the photographer or the visual designer of the asset. - *Description* - This optional field is used by editors to describe the asset. These core fields cannot be removed or redefined in the *Asset* model. ![core asset fields](https://assets-site.prepr.io/5e2abws8bb1p//asset-model.png) ## Add fields to the Asset model Sometimes the front end app needs more information about the asset beyond the *Title*, *Description* and *Author*. For example: If there is a requirement to display the copyright information with the image. In this case you can add more fields to the assets with the following steps: 1. From the **Schema** tab, click the *Asset* model. 2. Drag and drop one of the field types from the list on the right into the model. The following field types are available when adding fields to the assets: - [Text](/content-modeling/field-types#text-field) - Use this type to allow content editors to enter details like copyright information. The following settings are **not** available on the Text fields in the Asset model: - Unique constraint validation - Allowing scripts - AI features - **Links** option (in the HTML editor) - [Boolean](/content-modeling/field-types#boolean-field) - Use this field type to set a True/False indicator in the assets. - [List](/content-modeling/field-types#list-field) - Use the list field type for content editors to select values from an enumeration. - [Number](/content-modeling/field-types#number-field) - Use this field type to store number-related info in the assets. ![Add-asset-fields](https://assets-site.prepr.io/3s2fdrkkhjv//add-field-to-asset-model.png) ## Enable localization in assets In some cases, content editors need to enter asset information in different languages or define different info depending on the locale. For example: To include cultural context and nuances. To allow content editors to do this, you can enable [localization](/content-management/localizing-content) in the *Asset* model with the following steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the *Asset* model. 3. At the top of the model, click the **Settings** button to open the setting options. 4. Toggle the **Enable creation of language variants** switch to allow users to add language variants for each custom field added to the Asset model. ![Asset model - localization](https://assets-site.prepr.io/1hhrbofqmbg7//enable-language-variants.png) Source: https://docs.prepr.io/content-modeling/defining-the-asset-model --- # Managing Components *This article explains how to manage a component in Prepr. A component is a predefined set of fields that can be used in models.* ## Create a component To create a component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add component** button. 3. Name the component as follows [Or import a component](/content-modeling/managing-components#export-and-import-a-component): |General fields | Description| |--------------------------|--------------| |**Display name** |Choose a unique name for the component.| |**Type name**| The value of this field is automatically generated. This field is important for the GraphQL API to connect your front-end to Prepr. When you create a new component, this name is generated as follows: PascalCase version of the **Display name**, stripped of all non-alphanumeric characters. For example, the component name **"SEO tags"** generates **SEOTags**.| |**Icon**| Choose an icon image that visually represents your component. This is used for the dynamic content editor and other parts of the content item editor interface.| ![create-component](https://assets-site.prepr.io/2h4y9hca3kn4//add-a-new-component.png) After creating a component, you can include a component in a model. The following model fields allow you to use your component in a model: - [Component field](/content-modeling/field-types#component-field): This field type allows the model to include the component. - [Dynamic content field](/content-modeling/field-types#dynamic-content-field): This field type allows the component fields to be available in the **Dynamic Content Editor**. Check out the [Dynamic Content field type](/content-modeling/field-types#dynamic-content-field) for more details. - [Stack field](/content-modeling/field-types#stack-field): This field type allows the model to include multiple components and models. See an example empty component used as a placeholder, below: ![using empty components](https://assets-site.prepr.io/w_1920/s3-preprmarketing/308e420a-ecab-4dfe-a409-a614d46e1c9f.png) ## Duplicate a component In some cases you can duplicate a component to save time when you want to create a component that is similar to an existing one. To duplicate an existing component follow the steps below. 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the component you want to copy. 3. Click the button at the top of the component. ![duplicate a component](https://assets-site.prepr.io/287u9vd6zt3r//duplicate-component.png) 4. Click the **Duplicate component** option. The duplicate process is an automatic export and import of the component. 5. Once done, click the **Close** button. You'll see the duplicated component in the schema with **(Copy)** in the name. You can then rename and edit the duplicated component, as needed. For example, remove fields or add new fields. ## Manage settings To change settings for a component, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the component from the list of components on the left. 3. At the top of the components, click the **Settings** button to open the setting options for a component. The following settings are available: ### General The *General* tab allows you to edit the names and description for the component. ![Component general settings](https://assets-site.prepr.io/1rpyqua0bi2j//component-general-settings.png) |General fields | Description| |--------------------------|--------------| |*Display name* |A unique name for the component.| |*Type name*| This value is important for making requests with the GraphQL API. When you create a new component, this value is auto-generated as follows: PascalCase version of the display name, stripped of all non-alphanumeric characters. For example, the model name *News article* generates *NewsArticle*. |*Description*| A description to help editors manage content by showing the purpose of this model.| ### Appearance Click the *Appearance* tab to upload a preview *Image* or to set a *Tag* for the component. ![Component settings - Appearance tab](https://assets-site.prepr.io/3k48bnaq7bgg//component-appearance-settings.png) These settings help editors identify the component more easily in stack or reference fields. The preview image helps the editor visualize the content, while the tag puts the component into a logical group. ## Add fields to a component To add fields to your component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click on the component from the list of models on the left. 3. Drag and drop the desired field type, for example, **Text**, ![add field to component](https://assets-site.prepr.io/2unnqhutbo99//add-field-to-component.png) For a complete list and all the specs, check out all [Prepr field types](/content-modeling/field-types). Let's look at some basic settings that are common across all field types. 4. Using **Text** as an example, name it as follows: |General fields | Description| |--------------------------|--------------| |**Display name**| The field label shown in the content editing interface.| |**ID**| The value of this field is automatically generated. The technical ID of this field that is used, for example, to retrieve content through the API.| For more details on the other **Text** settings, check out the [Text field type](/content-modeling/field-types#text-field). 5. Click the **Validation** tab to set up validation rules for the field. Enable **This field is required** if this is a mandatory field. The validation only triggers when a content item is set to the **Done** stage. For more details, check out the [Workflow stages doc](/content-management/collaboration). For more details on the other **Text** validation options, check out the [Text field type](/content-modeling/field-types#text-field). ## Set a component title By default, the title of a component in a *Stack* or *Dynamic content* field is set to the first *Text* field in the component or to the value of the *Number*, *Content reference* or *List* field when the component only has one of these fields. At times, you may want the component title to be the title of a referenced content item. For example, when the embedded component title should be the headline of an article. Also, a component might just have a *List* or *Number* field, and in those cases, you might want the component title to be the chosen list item value or the number entered. For example, a number of the item that defines its order in a list. To set a *Text*, *Content reference*, *Number* or *List* field value as the component title, click the icon in the field and choose the **Set as title** option. ![Set value as component title](https://assets-site.prepr.io/48bjes3e47ra//component-set-as-title.png) ## Delete a component To delete a component, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the component from the list of components on the left. 3. Click the button at the top of the component. 4. Choose the **Delete** option. ![delete-component](https://assets-site.prepr.io/6lc6a9yisd0h//delete-component.png) ## Adding columns You can also use columns to determine the display of the fields in your content item. Columns are used to divide fixed content item fields into a maximum of three columns. To add columns, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click on the component from the list of components on the left. 3. Click the **+ Columns** button. 4. Drag the column element above the fields that you want divided into columns. 5. Choose the number of columns that you want those fields to be grouped into. ![add-columns-component](https://downloads-site.prepr.io/6u91ev3bdqeo-add-columns-to-component.gif) ## Create a nested component Nested components can be added to models directly, to a *Dynamic content* field or to a *Stack* field. This feature allows you to add an individual (*child*) component into another (*parent*) component, creating nested levels of content. You can reuse individual components as many times as needed, even if they're already used within nested components. For example, you can use a call-to-action component in both a page header component and a product collection component. To create a nested component, follow these steps: 1. [Create individual components](/content-modeling/managing-components#create-a-component) which represent different elements in your page layout, such as header, image and text, call-to-action, product or article collections, etc. 2. Determine a *parent component* – the one you’ll be using as a container for other components (*child components*). Click to open its configuration. 3. From the parent component page, add a new component field and select the needed child component. Save your choice. ![Nested component](https://assets-site.prepr.io/7ixp2rihsnkq//add-component-to-component.png) Now that you have created the nested component, you can [add it to a model directly](/content-modeling/field-types#component-field) or [place it within a Stack field](/content-modeling/field-types#stack-field). ## Organize components into folders When you have dozens of components, folders make it easy to find related components. For example, when you have multiple components which are used as sections of a page. Hover over the components and click the icon. Enter a name for the new folder and choose the components that you want to include in the new folder. Click the **Add folder** button. ![component folder](https://assets-site.prepr.io/1aa260pgvw3k//add-component-folder.png) To add or remove components from an existing folder, hover over the folder and click the icon. Choose the **Edit** option and select or deselect the components that you want to add or remove. You can also delete the folder by selecting the **Delete** option. The folder structure will be removed and the included components will return to the alphabetical list of components. ## Export and import a component Use the export and import if you only need a couple of components copied from one environment to another. For example, export a component from your staging environment and import the component into your production environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same components across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export a component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click the component that you want to export from the list of components on the left. 3. Click the button at the top of the component. 4. Click **Export component** to download a JSON file of the component. ![export-component](https://assets-site.prepr.io/30co5x7j1i4v//export-component.png) To import a component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add component** button. 3. Click **Or import a component**. 4. Choose the JSON file of the component that you want to import. ![import-component](https://assets-site.prepr.io/6ryrt92v3b9p//import-component.png) Source: https://docs.prepr.io/content-modeling/managing-components --- # Managing enumerations *This article explains how to create and use an enumeration in Prepr. An enumeration is a predefined list of values that can be used in models and components.* ## Create an enumeration To create an enumeration, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add enumeration** button. 3. Fill in a unique **Display name** value for the enumeration. 4) Add each of the list values and click the **Save** button. The *Name* values are visible to content editors. ![add enumeration](https://assets-site.prepr.io/3kbatzy002hf//add-enumeration.png) 5. Instead of adding each value manually, you can switch to the JSON editor to paste a JSON with all your values. Then click the **Save** button. ![Enumeration JSON editor](https://assets-site.prepr.io/30sapixzwxqy//add-enumeration-json-editor.png) Once your enumeration is created, it's ready for you to use in a model or component. ## Edit an enumeration You can edit the values in an enumeration by going to the button at the top of the enumeration and clicking the **Edit enumeration values** option. ![Edit enumeration values](https://assets-site.prepr.io/1kik80cw2lp5//edit-enumeration-values.png) You can then either edit the values manually or switch to the JSON editor to paste a JSON with your updated values. ![JSON editor example](https://assets-site.prepr.io/3xg6mnrhffit//edit-enumeration-values-in-json.png) Don't forget to click the **Save button** to save your changes. ## Duplicate an enumeration In some cases you can duplicate an enumeration to save time when you want to create an enumeration that is similar to an existing one. To duplicate an existing enumeration follow the steps below. 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click the enumeration you want to copy. 3. Click the button at the top of the enumeration. ![Duplicate an enumeration](https://assets-site.prepr.io/62kchzgdm41v//duplicate-enumeration.png) 4. Click the **Duplicate enumeration** option. The duplicate process is an automatic export and import of the enumeration. 5. Once done, click the **Close** button. You'll see the duplicated enumeration in the schema with **(Copy)** in the name. You can then rename and edit the duplicated enumeration, as needed. ## Add the enumeration to a model or component Go to the model or component where you want to include the enumeration and follow the steps below. 1. Add a *List* field to the model or component. Check out the [model](/content-modeling/managing-models#add-fields-to-a-model) and [component](/content-modeling/managing-components#add-fields-to-a-component) docs for more details. 2. From the **Select enumeration** dropdown, choose your enumeration. ![Add List field](https://assets-site.prepr.io/7gs4wvo3wsxb//add-enumeration-to-model.png) And that's it. You've successfully included your enumeration in a model or component. ## Organize enumerations into folders When you have dozens of enumerations, folders make it easy to find related enumerations. For example, when you have multiple enumerations which are used in the same components. Hover over the enumerations and click the icon. Enter a name for the new folder and select the enumerations that you want to include in the new folder. Click the **Add folder** button. ![enumerations folder](https://assets-site.prepr.io/2w61h511n7ij//add-enumeration-folder.png) To add or remove enumerations from an existing folder, hover over the folder and click the icon, Choose the **Edit** option and select or deselect the enumerations that you want to add or remove. You can also delete the folder by choosing the **Delete** option. The folder structure will be removed and the included enumerations will return to the alphabetical list of enumerations. ## Export and import an enumeration Use the export and import if you only need a couple of enumerations copied from one environment to another. For example, export an enumeration from your production environment and import it into your development environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same enumerations across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export an enumeration, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click the enumeration that you want to export from the list of enumerations on the left. 3. Click the button at the top of the enumeration. 4. Click the **Export enumeration** option to download a JSON file of the enumeration. ![export enumeration](https://assets-site.prepr.io/41z17rh13qj8//export-enumeration.png) When the export is successful, you'll find the JSON file in the location you selected. To import an enumeration, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add enumeration** button. 3. Click the **Import enumeration** link. 4. Choose the JSON file of the enumeration that you want to import. ![import enumeration](https://assets-site.prepr.io/1nc8u6nwu1gm//add-enumeration-json-editor.png) When the import is successful, you'll see the detailed enumeration in your schema. Source: https://docs.prepr.io/content-modeling/managing-enumerations --- # Setting up a built-in remote source *This article explains how to use a known 3rd party system as a remote source in Prepr.* ## Introduction Prepr allows you to use any external system as a remote source to reference images, videos, or other content in your content items. You can choose to connect to one of the predefined sources, such as Commerce Layer, and Commercetools, or add a custom one. To connect to a pre-built remote source, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Go to the **Remote sources** section and click the **Add source** link. 3. In the opened dialog window, choose to connect to the desired source. Prepr supports native content integrations with *Commerce Layer*, and *Commercetools*. ![Pre-built remote source](https://assets-site.prepr.io/3qy6n1hbhvyu//add-prebuilt-remote-source.png) 4. In the next screen, name and describe the source as follows, then click **Add**. ### Commercetools |Field | Description | | | | |----------------------- |-------------------------------------------------------------------------------------------------------------------------------------------- |--- |--- |--- | | **Display name** | A unique name to identify this source in Prepr. | | | | | **Type name** | A name used for accessing this source through the API. The value is generated automatically and matches the *Name* you specified. | | | | | **Project key** | The identifier of your [Project](https://docs.commercetools.com/api/projects/project). Copy the 'project\_key' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **Client ID** | Your [client credential](https://docs.commercetools.com/api/projects/api-clients) that is used to obtain an access token. Copy the 'client\_id' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **Secret** | Your [client credential](https://docs.commercetools.com/api/projects/api-clients) that is used to obtain an access token. Copy the 'secret' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **Scope** | The [scope](https://docs.commercetools.com/api/scopes) defines the endpoints to which a client has access and the permissions. Copy the 'scope' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **API URL** | The [endpoint URL](https://docs.commercetools.com/getting-started/make-first-api-call#url-and-endpoints) that is used to make the API calls. Copy the 'API URL' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **Authorization URL** | The [authorization URL](https://docs.commercetools.com/getting-started/make-first-api-call#auth-url-and-parameters) that is used to obtain an access token. Copy the 'Auth URL' value from [your API Client information](https://docs.commercetools.com/getting-started/create-api-client#view-your-api-client-configuration). | | | | | **Display locale** | Locale defines content language. Select a preferred language to use in the API requests to Commercetools. | | | | ### Commerce Layer | Field | Description | | | | |------------------ |-------------------------------------------------------------------------------------------------------------------------------------- |--- |--- |--- | | **Display name** | A unique name to identify this source in Prepr. | | | | | **Type name** | A name used for accessing this source through the API. The value is generated automatically and matches the *Name* you specified. | | | | | **Base URL** | The endpoint URL that is used to make the API calls. Copy the value from the [Commerce Layer API specification](https://docs.commercelayer.io/core/api-specification#base-endpoint). | | | | | **Client ID** | Your [client credential](https://docs.commercelayer.io/core/authentication/client-credentials) that is used to obtain an access token. Copy the 'client\_id' value from [your Integration API credentials](https://docs.commercelayer.io/core/api-credentials#integration). | | | | | **Secret** | Your [client credential](https://docs.commercelayer.io/core/authentication/client-credentials) that is used to obtain an access token. Copy the 'client\_secret' value from [your Integration API credentials](https://docs.commercelayer.io/core/api-credentials#integration). | | | | Once you've connected to one of the pre-built remote sources, Prepr will automatically create the necessary fields based on that integration. ![Pre-built source fields](https://assets-site.prepr.io/5v1pixdd3blt//commercetools-example-remote-source.png) ## What's next? Once you've set up the remote source, proceed with the following steps: 1. Add the remote source to your model using the [Remote content field](/content-modeling/field-types#remote-content-field). 2. Add remote content to your content items. 3. [Retrieve data using the API](/graphql-api/schema-field-types#content-integration) from your front end. Source: https://docs.prepr.io/content-modeling/setting-up-a-built-in-remote-source --- # Creating a custom remote source *Follow this guide to add 3rd party content to your web application using Prepr CMS.* ## Introduction When creating content items for your web application, you may want to reference content stored in an external system such as another CMS, legacy system, or eCommerce platform. With Prepr, you can easily use any 3rd party system as a remote source by following the steps below. To set up a custom remote source, Prepr CMS needs a connection to the external system through an API endpoint. ## Creating a custom API endpoint The first step is to create the API endpoint for your external system. When you create the API endpoint, make sure that the response matches the data format below so that Prepr can make calls to your external system. When the remote source is set up, Prepr calls the configured endpoint and expects at least one item to be returned. ### API response data format 1. Make sure the API response contains the following fields with the specified format: - `items` — an `array` of objects containing a list of items like products, for example. Each of these items have specific attributes to hold the details about each item. - `total` — an `int` field to hold the total number of items available. The total value also depends on the [search parameters](#supported-parameters) applied below. - `filters` (optional) - If you want to make it possible for content editors to filter groups of items when they add the remote items to a content item in Prepr CMS, include this `array` of filter criteria objects. See the detailed list of attributes below which are expected in the `items` array. | **Attribute** | **Type** | **Description** | Required | | ------------- | ------------- | ------------- |-------| | `id` | string | A unique item identifier. The identifier should not be reused when deleting an item. | ✓| | `body` | string | The title of the item. This value is visible in Prepr CMS when this item is searched or added to a content item. |✓| | `description` | string | The item description. This value is visible in Prepr CMS when this item is searched or added to a content item. |✓| |`image_url` | string | An image thumbnail URL. If this value is provided, the image of the item will be visible when this item is searched or added to a content item.|✗| | `external_url` | string | A URL to an external page, for example, to redirect an editor to the external system to manage the item directly. |✗| | `data` | object | This object contains a list of key-value pairs that holds additional details of the item that you want to render in the front end. The values can be a `string`, `int`, `float` or `boolean`. In [Step 2](#step-2-add-the-custom-remote-source-in-prepr), you will add these as fields in the *Remote source*. |✗| See the detailed list of attributes below which are expected in the `filters` array. | **Attribute** | **Type** | **Description** | Required | | ------------- | ------------- | ------------- |-------| | `body` | string | The title of the filter. This value is visible in Prepr CMS as the name of a filter. |✓| | `param` | string | The unique identifier of the filter that correlates to one of the keys specified in the `data` object in the `items` array defined above. If the filter is a range, set two filter entries for the minimum and maximum values. In this case, set the `param` value to the key combined with `[gt]` and `[lt]`, respectively. For example, `price[gt]` and `price[lt]`|✓| | `display_type` | string | This attribute tells the Prepr UI how to render the input for the filter value. This attribute should contain one of the following values: `text`, `checkbox`, `dropdown`, `toggle`, `date`, `date_range`. |✓| | `default_value` | string | Set this to the default value of the filter, if applicable. |✗| | `values` | array or object | The list of available filter values, if applicable. You can include the filter values simply as an array or as an object of the filter values with their corresponding display names. |✗| See an example response below of a list of products returned by a custom API endpoint for an external system. ```json copy { "items": [ { "id": "3177c1b8-a4e2-4a84-85e7-6a02cc0c5f98", "created_on": "2023-04-05T10:15:30+00:00", "changed_on": "2023-04-06T15:48:21+00:00", "body": "Ultimate Vegan Burger", "description": "A mouthwatering vegan burger packed with flavors and nutrients.", "image_url": "https://picsum.photos/200/300", "external_url": "https://veganburgerrecipes.com/ultimate-vegan-burger", "data": { "category": "Comfort food", "type": "Healthy", "ingredients": [ "black beans", "quinoa", "beetroot", "breadcrumbs", "spices" ], "cuisine": "International", "price": 8.99, "nuts": false, "cooking_time": 30, "created_on": "1974-12-18T10:37:49+00:00" } }, { "id": "bd78aeff-1c4a-49da-9cdf-c5ed5bc9c1a2", "created_on": "2023-04-05T08:20:15+00:00", "changed_on": "2023-04-05T08:25:15+00:00", "body": "Green Goddess Buddha Bowl", "description": "A nourishing bowl filled with a variety of greens and plant proteins.", "image_url": "https://source.unsplash.com/featured/?salad", "external_url": "https://example.com/recipes/detail/vegan-goddess-bowl", "data": { "category": "Light", "type": "Main", "difficulty": "easy", "ingredients": [ "kale,quinoa", "avocado", "cucumber", "chickpeas", "pumpkin seeds" ], "cuisine": "International", "price": 9.5, "nuts": false, "cooking_time": 30, "created_on": "2004-09-18T22:45:56+00:00" } }, { "id": "90870c84-d3a4-437b-a9b6-96388cabf0fa", "created_on": "2023-01-21T14:25:30+00:00", "changed_on": "2023-01-30T16:40:45+00:00", "body": "Hearty Vegan Stew", "description": "A delicious and warming stew that's perfect for cold weather and cozy nights in.", "image_url": "https://picsum.photos/id/169/200/300", "external_url": "https://vegancooking.example.com/recipes/341576", "data": { "category": "Comfort food", "type": "Main", "difficulty": "medium", "ingredients": [ "potatoes", "carrots", "lentils" ], "cuisine": "International", "price": 6.99, "nuts": false, "cooking_time": 45, "created_on": "2015-09-28T03:22:55+00:00" } }, { "id": "e9a48d63-689a-4cf1-b5fa-307d7fae8910", "created_on": "2023-03-10T08:35:23+00:00", "changed_on": "2023-04-01T15:46:07+00:00", "body": "Vibrant Vegan Salad Bowl", "description": "A colorful array of fresh vegetables and quinoa, perfect for a nutritious lunch or dinner.", "image_url": "https://picsum.photos/200/300", "external_url": "https://example.com/recipes/vegan-salad-bowl", "data": { "category": "Keto", "type": "Main", "difficulty": "easy", "cuisine": "International", "nuts": false, "price": 8.99, "cooking_time": 15, "created_on": "2013-11-13T21:00:00+00:00" } }, { "id": "8ba2b831-960b-4cc3-baad-9b153c6d1295", "created_on": "2023-02-15T08:30:20+00:00", "changed_on": "2023-03-18T15:45:10+00:00", "body": "Vegan Lentil Soup", "description": "A hearty and nutritious lentil soup, perfect for any season.", "image_url": "https://images.unsplash.com/photo-1587502537745-84b86da1204f", "external_url": "https://example.com/recipes/vegan-lentil-soup", "data": { "category": "Comfort food", "type": "Starter", "difficulty": "easy", "cuisine": "International", "price": 5.99, "nuts": false, "cooking_time": 25, "created_on": "2015-09-01T00:00:00+00:00" } }, { "id": "ee94e136-e8b6-456e-8dbd-d176bfcce8e7", "created_on": "2023-03-15T10:56:03+00:00", "changed_on": "2023-03-18T09:34:05+00:00", "body": "Sizzling Vegan Stir-Fry", "description": "A delightful vegan stir-fry packed with fresh vegetables and tofu.", "image_url": "https://source.unsplash.com/weekly?vegan", "external_url": "https://example.com/vegan-stir-fry/9923458294", "data": { "category": "Light", "type": "Appetizer", "difficulty": "easy", "cuisine": "Asian", "price": 8.99, "nuts": false, "cooking_time": 20, "created_on": "2013-06-25T23:45:00+00:00" } } ], ... "total": 43 } ``` 2. Define headers to add authentication or filters required by the API endpoint. 3. Make sure that your endpoint supports **pagination** with the parameters defined below. ### Supported parameters To learn more about how Prepr interacts with the API endpoint, consider the following: - **Automatic synchronization.** To keep your remote content constantly updated in Prepr, your custom API must support filtering on the last changed items. In this case, Prepr will call the API with a `changed_since` param to refresh your items every 15 minutes. For example, `website.com/prepr/feed?changed_since=1583414373` (UNIX Timestamp). - **Pagination.** The API must work with the `skip` and `limit` params to paginate params, and the API response should contain a maximum of 50 items. For example, - Page 1: `website.com/prepr/feed?skip=0&limit=50` - Page 2: `website.com/prepr/feed?skip=50&limit=50` - Page 3: `website.com/prepr/feed?skip=100&limit=50`, etc - **Search.** To help editors search for a remote content item, Prepr calls the external system URL with the `q` param containing the editor's input, for example, `website.com/prepr/feed?q=Looking%20for%20an%20item`. In this case, the total response will be updated with the filtered number of matching items. - **Locale.** To help editors search for a remote content item, Prepr calls the external system URL with the `Prepr-Locale` header. This header, which is based on ISO 639-1 standards (e.g., `en-US`), reflects the editor's current viewing language. This feature enables you to customize your feed according to the viewing language. (This is necessary only if your feed supports multiple languages). - **Filter.** To help editors filter remote content items, Prepr calls the external system URL with one or more parameters that match the `param` values in the `filters` array in the API endpoint, for example, `website.com/prepr/feed?category=Comfort%food&type=Main`. In this case, the total response will be updated with the filtered number of matching items. ### Filtering remote content You can add filters to the API endpoint to allow content editors to filter the items from the remote source in Prepr. The filters make it easier for content editors to find the remote content they need to add to the content item in Prepr. ![remote content filters](https://assets-site.prepr.io/6g63uvzvx9ce//remote-content-filters.png) To make these filters available to content editors make sure that the API response data format includes the `filters` field as defined in the [section above](#api-response-data-format). Filters can be dynamically adjusted based on filter values or searches. Check out the example response below with filters and possible `display_type` values: ```json copy { "filters": [ { "body": "Product Id", "param": "id", "display_type": "text" }, { "body": "Category", "param": "category", "display_type": "dropdown", "values": { "light" : "Light", "healthy" : "Healthy", "comfort-food" : "Comfort food", "keto" : "Keto" } }, { "body": "Meal type", "param": "type", "display_type": "checkbox", "values": { "appetizer" : "Appetizer", "starter" : "Starter", "main" : "Main", "dessert" : "Dessert" } }, { "body": "Price", "param": "price[gt]", "display_type": "checkbox", "default_value": "", "values": [ 0.00, 6.00, 10.00 ] }, { "body": "Price", "param": "price[lt]", "display_type": "checkbox", "values": [ 5.99, 9.99, 12.99 ] }, { "body": "Prep time", "param": "cooking_time", "display_type": "checkbox", "default_value": "", "values": [ 15, 20, 25, 30, 45 ] }, { "body": "Contains nuts", "param": "nuts", "display_type": "toggle", "default_value": true }, { // The expected date format is YYYY-MM-DD, like 2024-02-28 "body": "Creation date", "param": "created_on", "display_type": "date" }, { // The request will be made with an array containing a from and until value formatted YYYY-MM-DD "body": "Creation date", "param": "created_on", "display_type": "date_range" } ], "items": [ ... ], "total": 43 } ``` ## Adding the custom remote source in Prepr Now that you’ve set up your custom API endpoint, proceed with the configuration in Prepr. You’ll need to connect Prepr to your external system using the API credentials. To add a custom remote source, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. On the **Schema Editor** page, navigate to the **Remote content** section and click **+ Add source**. 3. In the opened dialog window, choose to add a custom source. ![Add custom remote source](https://assets-site.prepr.io/4kqecah3qe8f//add-custom-remote-source.png) 4. In the next screen, name and describe the source as follows, then click **Add**. | Field | Description | |------------------ |------------------------------------------------------------- | | **Display name** | A unique name to identify this source in Prepr. | | **Type name** | A name used for accessing this source through the API. The value is generated automatically and matches the *Name* you specified. | | **Text in button** | The text in the button that will add the items to the content item. | | **Icon** | An icon to identify this source in a content item. | | **Endpoint URL** | The endpoint URL that is used to make the API calls. Refer to your external system API specification. |\ | **Image domain(s)** | An image domain to be allowed in Prepr. It guarantees Prepr will use only domains approved for authorized access to images. |\ | **Header** | Add the key-value pair to pass additional information about your API request such as the authorization token. This key-value list will be sent in the header of the API request. | ![Add custom source details](https://assets-site.prepr.io/7b5n893cfcik//add-custom-remote-source-details.png) 5. Add fields to your remote source in Prepr and map them to the corresponding fields in the external system as defined in the `data` object above. You can then fetch these fields using the [GraphQL API](/graphql-api/schema-field-types#remote-content) to deliver remote content in your front end. a. To add fields to the remote source, drag and drop the desired field type from the list on the right into your source. You add a [Text](/content-modeling/field-types#text-field), [Boolean](/content-modeling/field-types#boolean-field) or [Number](/content-modeling/field-types#number-field) field. ![Select a field](https://assets-site.prepr.io/11fa6r12m7uv//add-field-to-custom-resource.png) b. Then, set the *Name* to the Prepr field name and set the *Source API ID* to the corresponding field name from your external system: ![field details - custom remote source](https://assets-site.prepr.io/7hoxnjxzznne//field-details-custom-resource.png) Now you can add the [Remote content field](/content-modeling/field-types#remote-content-field) to the applicable model to allow content editors to include remote content in their content items. ## Next steps Once the remote source is set up and editors have [included the remote content](/content-management/managing-content/creating-rich-content#adding-remote-content) in their content items, you can [retrieve the remote content](/graphql-api/schema-field-types#remote-content) for those content items using the GraphQL API. Source: https://docs.prepr.io/content-modeling/creating-a-custom-remote-source --- # 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. ## 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 + 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 + 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.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 + 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 --- # Gatsby + Prepr CMS Need info on Prepr for a Gatsby app? Look no further. This all-in-one page gives you all the resources you need to connect your project to Prepr. ## Gatsby 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/gatsby --- # Node.js + Prepr CMS This is the official Node.js + Prepr guide. It’ll explain to you how to quickly set up a Prepr client in your Node application and use it to fetch data from the Prepr CMS. ## Getting started In this guide, you’ll follow an example that’ll teach you how to set up a minimalistic Node application making use of Express (a Node framework), set up a Prepr client and serve the data received using it to the client through a get request. ## Prerequisites This guide assumes that you’ve: - An active Prepr account. - Set-up an environment on Prepr CMS, preferably using the demo data provided by Prepr. This can be done by clicking on Load demo data when setting up the environment. ## Setting up a Node application To begin, create a directory for your application and enter it using the following commands: ```bash copy mkdir prepr-node cd prepr-node ``` Initialize your project using `npm init -y`. Install necessary packages: ```bash copy npm install express nodemon dotenv ``` Update your `package.json` file to have `app.js` as your main entry point and include the following watch script under scripts: ```js copy "watch": "nodemon app", ``` Now, create a file named app.js using touch app.js and add the following code into it: ```js copy const express = require("express"); const app = express(); const port = process.env.PORT || 3000; app.get("/", (req, res) => { res.send("Hello world"); }); app.listen(port, () => { console.log(`App listening on port: ${port}`); }); ``` Run the application using following command: ```bash copy npm run watch ``` Now, upon visiting `http://localhost:3000/`, you should see the following output: ![Localhost:3000](https://assets-site.prepr.io/w_1920/s3-preprmarketing/237bef2b-0ac4-4923-b05d-065c934c8e72.png) ## Creating a Prepr client Close the server you started in the above step and add the Prepr’s Javascript SDK to your app by using the following command: ```bash copy npm install @preprio/nodejs-sdk ``` Create a `services` directory in the root of your project and in here, create a file named `prepr.js` using the following commands: ```bash copy mkdir services cd services touch prepr.js ``` You’ll use this file to create and configure your Prepr client with the help of `createPreprClient` provided by the SDK. The client will be used to make API requests to endpoints provided by the Prepr CMS in your Node application. Add the following code to this file: ```js copy require("dotenv").config(); const { createPreprClient } = require("@preprio/nodejs-sdk"); const prepr = createPreprClient({ token: process.env.PREPR_ACCESS_TOKEN, // You can find one in your Prepr environment baseUrl: "https://graphql.prepr.io/graphql", userId: null, // Optional, used for AB testing implmentations }); module.exports = { prepr }; ``` Prepr recommends using environment variables to store your sensitive information like access token. To add environment variables, create a `.env` file in the root directory of your project and add the variable like this: ``` PREPR_ACCESS_TOKEN= ``` ## Writing GraphQL query Now, let’s write the GraphQL query that you’ll use in this example. Create a `queries` directory in the root of your project and in here, create a file named `preprQueries.js` using the following commands from the root of your project: ```bash copy mkdir queries cd queries touch preprQueries.js ``` Add the following code to this file: ```js copy const GetPosts = ` query GetPostsQuery { posts: Posts { items { _id _slug title } } }`; module.exports = { GetPosts }; ``` If you’re using the same preloaded demo data in your CMS environment as mentioned above in the Prerequisites section, you should have 5 posts in there. This query, GetPosts, will be used to fetch the post titles. In case, you’re not using the demo data provided by Prepr then your query might be different. To test your query, you can make use of [Explorer](https://studio.apollographql.com/sandbox/explorer) provided under Apollo Studio’s sandbox mode. There you can easily create a query with the help of the documentation pane and check the results in real time. All you’ll need is your unique graphql endpoint, All the necessary information about the endpoint can be found [here](/graphql-api/authorization). ## Fetching and sending data as response Open `app.js` in the root of your project and replace its content with the following code: ```js copy const express = require("express"); const { prepr } = require("./services/prepr"); const { GetPosts } = require("./queries/preprQueries"); const app = express(); const port = process.env.PORT || 3000; const posts = []; const preprData = async () => { const postsData = await prepr.graphqlQuery(GetPosts).fetch(); posts.push(...postsData.data.posts.items); }; preprData(); // Query for the root path. app.get("/", (req, res) => { res.send({ data: posts }); }); // Listen to application port. app.listen(port, () => { console.log(`App listening at http://localhost:${port}`); }); ``` What you’re doing here is importing the Prepr client and the GraphQL query you created in above sections into your `app.js`. Then you run the GraphQL query, `GetPosts`, using the Prepr client and push the data received into the posts array initialized right above it. Finally, you send the posts as response to the get request on the root path of your server. Run the application again using the `watch` script. Now, upon making a get request against your server’s root path or visiting it in the browser, you should see a similar response as shown in the image below: ![Localhost result](https://assets-site.prepr.io/w_1920/s3-preprmarketing/eccc48f7-24c4-4115-86f7-0558a31b40be.png) ## Learn more For additional information on using @preprio/nodejs-sdk, checkout its [documentation](https://github.com/preprio/nodejs-sdk). Source: https://docs.prepr.io/connecting-a-front-end-framework/nodejs --- # 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 + 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 + 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 --- # Why you don't need an SDK with Prepr CMS When implementing a headless CMS, you might assume you need to use a dedicated SDK to include Prepr CMS in your front end. Since Prepr CMS includes a GraphQL API for content delivery, using *Apollo Client* or a similar GraphQL client to fetch content eliminates the need for an SDK. ## Apollo Client already handles everything you need [Apollo Client](https://www.apollographql.com/docs/react) is a powerful GraphQL client that simplifies data fetching and management. It provides: - Querying so you can fetch content directly with GraphQL. - Built-in caching mechanisms to improve performance and reduce API calls. - State management to normalize data and manage it efficiently. Since GraphQL APIs are self-documenting and strongly typed, *Apollo Client* allows you to interact directly with the CMS without requiring additional SDKs. ## Apollo Client is scalable *Apollo Client* is scalable because it's optimized for edge deployment and serverless applications as follows: - It comes with normalized cache that reduces redundant requests and optimizes data retrieval, improving performance in distributed environments. - It minimizes network requests by batching queries and deduplicating them, which is beneficial for scalable applications. - It works well with edge computing platforms by reducing latency and improving data fetching performance. - It integrates seamlessly with serverless GraphQL APIs (like Apollo Server running on AWS Lambda). ## Easier debugging and tooling Apollo Client integrates seamlessly with developer tools like *Apollo DevTools*, making it easier to inspect queries, analyze cache, and debug issues—capabilities that may not be as robust when using a CMS-specific SDK. ## Next steps Check out [one of the framework quick start guides](/connecting-a-front-end-framework) to get you started in a few minutes to implement your front end using [Apollo Client](https://www.apollographql.com/docs/react). To make the most of all Prepr features including A/B testing and personalization, check out the [Next.js complete guide](/connecting-a-front-end-framework/nextjs/next-complete-guide). Source: https://docs.prepr.io/connecting-a-front-end-framework/using-an-sdk --- # Developer fundamentals guide *In this guide, you'll find everything you need to know to develop with Prepr CMS. At a high level, it introduces you to essential concepts and guides you toward more information about these concepts.* ## Understanding the architecture It's important to understand the architecture of a headless CMS for you to make the best decisions for your approach, technical designs, testing and deployment. Here are some key concepts to consider before you get started. - **Decoupled backend and frontend**: Unlike a traditional CMS, a headless CMS provides content via APIs. Content management and presentation are completely separate. This makes it easier for you to build flexible, multi-platform experiences. - **API-first approach**: Familiarize yourself with the APIs that the CMS exposes. Prepr CMS exposes a GraphQL API for fetching content and a RESTful API for managing content. - **Microservices mindset**: A headless CMS often fits into a modular web architecture (MACH). In this setup each component, such as search or authentication, is a microservice that needs to be integrated seamlessly. ## Developing with a headless CMS The steps listed below give you a high level outline of the activities you can expect when developing with a headless CMS. We trust that we have guided you to implement a successful web app with Prepr CMS. Are you missing some developer-related resources or specific info, [please let us know](https://forms.gle/B4SezB1rhzEqeGLe8). Source: https://docs.prepr.io/development/fundamentals --- # Best practices for developers *Check out our offering of best practices to develop streamlined and robust code for a headless CMS.* Source: https://docs.prepr.io/development/best-practices --- # Working with CI/CD Discover advanced Prepr CMS features designed to support your CI/CD processes. Source: https://docs.prepr.io/development/working-with-cicd --- # Managing content *Learn about managing content items, improving SEO and readability and creating rich content in Prepr CMS.* Source: https://docs.prepr.io/content-management/managing-content --- # Managing assets *Learn how to upload, manage and store your assets centrally in Prepr CMS to create photo galleries, video blogs, or even start a live-streaming event in your web application.* Source: https://docs.prepr.io/content-management/managing-assets --- # Reviewing content This guide provides you details on content management features you can use to help you review your content items. These help you identify and fix common issues like missing fields, broken links, and nonoptimal SEO. You can review content using the following key features: - *Content check* - *Needs attention* view ## Content check When creating a new content item or editing an existing content item, you can trigger the *Content check* when it's [enabled for the corresponding model](/content-modeling/managing-models#enable-content-check). ![Review content automatically gif](https://downloads-site.prepr.io/850bxa8dakt-content-check.gif) The content check helps you review the content for a number of issues: - Empty required fields and values exceeding a character limit length - Broken links - [Nonoptimal SEO values](/content-management/managing-content/optimizing-content-for-seo) ## Needs attention view You can easily find content items with content quality issues by clicking the **Needs attention** view in the sidebar of the **Content** page. Click to open a content item directly from this list and fix the issue. ![Needs attention example gif](https://downloads-site.prepr.io/6o64trah77mx-needs-attention-view.gif) The list of content items in the **Needs attention** view include the following types of issues: - Content items with broken internal or external links. - Content items that could not be published because the workflow stage is not set to *Done*. Source: https://docs.prepr.io/content-management/reviewing-content --- # Localizing content ## Working with localization Multi-channel content publishing also means managing content in different languages. Prepr offers unlimited locales for your content. Effortlessly localize your content into any language. Assign local versions to different users with a dedicated workflow and scheduling for their location. ### Adding a locale Every Prepr environment contains a default locale. You can recognize this locale by its ISO code (i18n), for example, `en-US` or `de-DE`. Each environment has its own set of locales. To add a new locale, follow the steps below. 1. Click the icon and choose the **Locales** option. Here, you can select one or more locales for multi-language content items and set a default. 2. Choose the locale value from the drop down to add a new locale to the environment and click the **Save** button. ![Adding a locale](https://assets-site.prepr.io/566ziagk4hdx//settings-locales.png) ### Working with multiple locales If your Prepr environment is set up with multiple locales, you can see a summary of the locale versions for a content item from the content item list by going to the **Content** page. To see the workflow summary for each locale, hover over the user icon of a content item. ![hover on user](https://assets-site.prepr.io/53u1ugrkuh8n//content-item-list-view-locale-and-workflow-summary.png) To see the status of each locale for a content item, hover over the status info like in the example below. ![hover on status](https://assets-site.prepr.io/7l6nj668u588//content-item-list-view-status-summary.png) You can also filter your content items by language in the **Content** page. Click the *Language* filter at the top of the content item list with the default locale selected. The content item title in the content item list is the title in the default locale. ![Working with multiple locales](https://assets-site.prepr.io/23dl7lsysb2d//content-item-list-filter-by-locale.png) #### Default locale When you log in to Prepr, the content items are listed in the default locale. When you create a content item, this item also starts in the default locale. The default locale is set for the [environment](/project-setup/setting-up-environments#create-an-environment), but you can override this value by setting a default locale in your profile when it's allowed for your user role. To set your own default locale, click your user avatar at the top of the screen and choose the *Profile* option and update your **Language preference** in the *Settings* section. Click the **Save** button to save your user preferences. ![user settings](https://assets-site.prepr.io/54i0mkxhe4fa//account-profile-language-preference.png) ### Create a language variant If you want to create another language variant, go to your main content item and choose the language from the drop-down menu in the side bar. In the drop-down menu, you can see the workflow stage of each locale entry, for example, *Not created*, *To do*, *In progress* or *Done*. A modal then opens from which you can click one of the following options: - *Translate automatically using AI* - Choose the source language if more than one is available and then choose the tone of voice or click the **Skip** button to start automatic translation. Prepr translates the text and creates the content item entry in your chosen language. You can then update this content item entry to refine the translated text. ![AI translate content item gif](https://downloads-site.prepr.io/2cl1e74cq9jv-ai-translate-content-item.gif) - *Copy content and translate manually* - Choose the source language that you want to copy. Prepr creates a copy of the content item with the exact same text. You can then translate the text manually. - *Start from scratch*. - Prepr creates a content item with empty fields. You can then fill the content item from scratch. ## Working with assets in multi-language content items Do you want to use and describe one asset in different content items? That is facilitated by Prepr: it is possible to add a caption to the asset(s) per content item. In this way, you can have the caption in one content item deviate from the caption in the other content item. This is how you can describe the asset very precisely for your specific content item. ### Manage captions in multi-language content items Do you work with content items in multiple languages? 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. To manage the caption in an asset per language, follow the steps below. 1. Go to the **Content** tab and select the right content item. Hover over the thumbnail of the image you want to edit and click the icon. Choose the **Edit caption**. 2. Enter a caption the matching language and click the **Save** button. 3. Save the content item and switch to another locale. 4. Repeat the above steps to edit the caption for the same image in a different language. 5. Save the content item to apply the new caption. ![Add caption to another image](https://downloads-site.prepr.io/3kvqcxs1hukx-manage-multi-language-captions.gif) Source: https://docs.prepr.io/content-management/localizing-content --- # Collaborating with coworkers ## Manage workflows Use workflows to assign content items to team members, work together smoothly, and manage content easily with a Kanban board, commenting, and notifications. ### Workflow stage A workflow is the lifecycle of a content item from its creation until it's done and ready to be published. Explore the below workflow stages to leverage its power in Prepr. ![workflow stages](https://assets-site.prepr.io/6i481i8t31ef//workflow-stages-content-item-example.png) #### To do When you create a new content item, it is first set to the *To do* stage. This means that you have yet to start work on this content item. *To do* content items are typically items in which raw text has been entered with many missing fields. #### In progress The moment the content item is further compiled by you or your team, the stage is updated to *In progress*. The content item is built and all fields are now filled with the correct content. You can save content items in this stage, even if required fields have not been entered. #### Review When the content item is almost finished and needs a final check, set the workflow stage to *Review*. If someone else has to review your work, you can [assign this content item to someone else](#assignees). You can save content items in this stage, even if required fields have not been entered. #### Done The content item is finished and does not need any further adjustments. The content is set to *Done* automatically when the content item is published. Check out the [Manage content items doc](/content-management/managing-content/managing-content-items) for more details. You can only save content items in the stage *Done* if all required fields have been entered. #### Archived A content is automatically *Archived* when the *Unpublish on* date and time is set on the content item and has been reached. #### Custom workflow stages The workflow stages listed above are predefined in your Prepr environment. If you need additional stages to match your content creation process such as a *Translate* stage, your environment administrator or owner can add a custom workflow stage. Check out the [environment settings](/project-setup/setting-up-environments#workflow-stages) for more details. ### Assignees You can assign content items to a user and filter the content item list by assignee, making it easier to focus on the items you need to work on. To assign a content item to another user, follow the steps below. [//]: # "1. Go to the **Content** tab and select the content item you want to assign. " 2\. Simply click the *Assigned to \[Name]* or *Unassigned* text at the top of the page to open the user search bar. 3\. Search for and choose the user you want to assign the content item to. You can assign the content item to yourself or to another user. ![assignees](https://assets-site.prepr.io/4k5o6ithofus//collaboration-assignee.png) To get a clear overview of all content items that have been assigned to a specific user, you can filter the content item list by the *Assignee*. Click the user for whom you want to see all content items. Select *Assigned to me* if you want to see all content items that you have to work on. ### Commenting You can make internal comments for a content item, for example, while reviewing the content. Follow the steps below to add a comment. [//]: # "1. Go to the **Content** tab and select the content item you want to comment on. " [//]: # "2. Click the button at the top right of the page to open the action list and choose **Comments**. This can be useful when they need to review the content item." 3\. Enter your comment. 4\. To notify another user, you can mention them in your comment with an `@`, type their first initial and choose their name from the list of users. ![commenting](https://assets-site.prepr.io/2jv9nf0dgful//collaboration-commenting.png) 5. Click the **Add comment** button to save your comment. Your co-worker will receive an email [notification](#notifications) and a notification in Prepr at the top of the screen with a link to the right content item. ### Kanban view [//]: # "At the top right of the content item list, switch from the *List view* to the *Kanban* view. " Here you can see the content items by each of the workflow stages. In this view, you can easily drag and drop a content item to update the stage. ![kanban view](https://downloads-site.prepr.io/2g57jad0wdkc-kanban-view.gif) ### Notifications When you assign a content item to someone else or mention them in a comment, they will receive a notification in Prepr at the top of their screen and a notification by email within a few minutes. The link in the email will lead them directly to the right content item. ![notifications](https://assets-site.prepr.io/hyp9gv9yc4t//notifications.png) When another Prepr user starts working in the same content item as you, this will be visible above the save button. ![collaborators](https://assets-site.prepr.io/6u6sldbylyr7//collaboration-different-users-in-the-same-content-item.png) Source: https://docs.prepr.io/content-management/collaboration --- # Data collection fundamentals *In this guide, you'll find essential concepts about data collection for Prepr CMS.* ## Introduction Data collection is the process of tracking and recording information about how web app visitors engage with content. The data gathered helps you understand visitor behavior, optimize content, and drive business decisions. The key concepts below provide a clear understanding of what data collection means for a front-end application that uses Prepr CMS. ## Event-based system {/* Prepr CMS offers several data-driven features such as personalization, 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. */} Prepr CMS is an event-based system, offering powerful insights into web app visitor interactions. You can therefore capture these interactions (events) as they happen. Each event represents a distinct action, such as viewing content, clicking a button, or making a purchase. Now that you understand how important events are in Prepr CMS, let's look at an event more closely. ## Anatomy of an event An event consists of three components: the content item, the action performed, and the visitor performing the action in the web app. In Prepr CMS, any visitor that interacts with your web app is known as a *Customer*. Let's take a look at an example where customer *12345* views the home page of your website. *12345* is the customer, the *Home page* is the content item, and viewing is the action. ![anatomy of an event](https://assets-site.prepr.io//3itkhkqog2gs-anatomy-of-an-event.png) By understanding who did what and with which content, you collect the data you need for A/B testing, personalization and recommendations. In the above example, a view action is the event type. Let's go a step further and look at different event types. ## Event Types Different types of events track different ways that visitors interact with a web app. Categorizing events allows you to filter and analyze data more effectively. Check out [how to record events in Prepr](/data-collection/recording-events) for more technical details. |Event type| Definition| |----------| ----------| |[View](/data-collection/recording-events#view)| You can use a view event to record a customer viewing a content item, like a home page or an article, or when a customer scrolls to a specific element in a page, like a testimonial. | |[Like](/data-collection/recording-events#like)| You can use a like event when a customer clicks a link or button to indicate their approval or interest. When the same customer clicks to undo their like, you can then record the *Unlike* event. | |[Bookmark](/data-collection/recording-events#bookmark)|A bookmark event is typically when a customer clicks a link or button to save a piece of content to view later. When the same customer clicks to remove their bookmark, you can then record the *Unbookmark* event.| |[Subscribe](/data-collection/recording-events#subscribe)|A subscribe event is usually when a customer clicks a link or button to subscribe to a newsletter, content updates, or other recurring content notifications. When the same customer clicks to cancel their subscription, you can then record an *Unsubscribe* event.\ |[Sign up](/data-collection/recording-events#signup)|You can use a sign up event when a customer creates a new account or registers on your web app. This event is not related to any content item, but to a specific customer. This event is useful when your web app uses an identity provider to manage customers.| |[Custom events](/data-collection/recording-events#recording-custom-events)|If you have another type of interaction that you want to track and record to segment customers, you can record a custom event in Prepr, such as a *Purchase* event. | Now that you understand different event types, let's look at how data collection supports personalization, A/B testing and recommendations. ## Data collection and personalization Data collection enables the [creation of customer segments](/personalization/managing-segments) for personalized content. By collecting event data related to customer behavior, you can identify patterns and group users into segments with similar interests or behaviors. By segmenting customers based on their event data, you can offer tailored content, improving relevance and boosting performance metrics. For example, a virtual car leasing company (*Acme Lease*) wants to track and record when customers view content items related to electric cars, like their *Electric car landing page*. To do this, they send a *View* event to Prepr for each customer who opens the *Electric car landing page*. They can then choose to create a segment for customers who prefer electric cars. Check out the [setting up personalization guide](/personalization/setting-up-personalization) for more details. ## Data collection and A/B testing A/B testing involves comparing two variants of a web page to evaluate which performs better. The variants of an A/B test are typically measured by impressions, when customers view certain elements on a page, and conversions, when customers click certain links or buttons. A/B testing helps you make data-driven decisions. By evaluating how different variants impact customer behavior, you can optimize experiences, increasing conversions and engagement. When you want to create metrics for impressions and conversions in Prepr, you can set up special attributes in the HTML of your web pages. - One attribute defines an impression on an element in the web page, like the header. When a customer views this element, an impression is then automatically sent to Prepr. - Another attribute defines a conversion for a button or link in that element. When a customer clicks this link or button, a conversion is automatically sent to Prepr. Check out the [A/B testing guide](/ab-testing/setting-up-ab-testing#add-html-attributes-to-track-impressions-and-conversion-events) for more details. ## Data collection and recommendations Event data can be used to generate personalized recommendations based on content popularity and customer behavior. By analyzing which content items are frequently viewed together, you can make relevant suggestions to customers. Recommendations drive engagement by helping users discover content that aligns with their interests. Popularity-based recommendations, powered by event data, help customers find what others have enjoyed, increasing overall satisfaction and time spent on the platform. Prepr automatically generates recommendations for *People Also Viewed* and *Popular items* lists when you track and record view events. You can then easily [retrieve recommendations from the API](/recommendations) for these lists. Now that you understand the key data collection concepts, check out the [step-by-step guide](/data-collection/step-by-step-guide) on how to collect data. Source: https://docs.prepr.io/data-collection/fundamentals --- # Step-by-step data collection guide *This guide takes you through the high level steps to implement data collection for Prepr CMS.* ## Collecting customer data in Prepr You can gather valuable insights from your customers by setting up efficient data collection in Prepr CMS. Follow the steps below to get these insights and use them to optimize your web app. We trust that we've guided you to set up data collection in Prepr CMS. Are you missing some resources or specific info? [Please let us know](https://forms.gle/B4SezB1rhzEqeGLe8). Source: https://docs.prepr.io/data-collection/step-by-step-guide --- # Setting up Prepr tracking *This guide takes you through installing Prepr tracking, testing this setup, and additional tracking options.* ## Introduction Installing Prepr tracking allows you to capture customer data and lets you track how customers engage with your content. This is an essential step when setting up personalization, A/B testing and recommendations. Even before implementing personalization, it also helps your digital teams gather useful insights for [segmentation](/personalization/managing-segments). If you haven't yet done so, check out the [Fundamentals guide](/data-collection/fundamentals) for key data collection concepts. And for an overview of the high-level steps needed for data collection, check out the [Step-by-step guide](/data-collection/step-by-step-guide). The steps below show you how to enable Prepr Tracking in your web app and start collecting data right away. ## Enabling Prepr tracking Prepr uses a lightweight piece of JavaScript to capture customer data and events. Follow the steps below to enable Prepr tracking in your web app. 1. Click the icon and choose the **Event tracking** option to view the *Prepr Tracking Code*. ![event tracking page](https://assets-site.prepr.io/6tdbnw4g3051//prepr-tracking-code-example.png) 2. Click the **Copy code** link to get a ready-to-use *Prepr Tracking Code* and add it to the `` section of your web-app. Once you've set up Prepr tracking in your front-end app, you can then [add simple meta tags](/data-collection/recording-events#initial-setup-with-meta-tags) to your web app to track events for customers on specific content items. ## Testing event tracking Before sending event data to Prepr, it's important to test that the above setup was done correctly. You can test it directly in your browser with the steps below. 1. Simply navigate to any page in your web app. 2. Right-click anywhere in the page and click the *Inspect* option. 3. Click the *Network tab* and refresh the content page. 4. Choose the **All** button and enter *pixel.gif* in the *Filter* textbox. ![Check pixel from browser](https://assets-site.prepr.io//54refr2jnaeo-check-pixel-from-browser.png) You'll see the tracking request with a `200 OK` status. Great! Prepr tracking is installed successfully. You are ready to [record some events](/data-collection/recording-events) depending on your needs for personalization and A/B testing. ## Sending events to Google Tag Manager (GTM) To send experiment-related events (such as impressions of content variants, A/B experiments, or segmented views) to Google Tag Manager, you can enable the built-in GTM integration in the [Prepr Tracking Code](#adding-the-tracking-code). This allows you to reuse the data collected by Prepr for reporting and personalization pipelines in Google Analytics 4 (GA4) or other GTM-connected services. To activate this, you simply need to update your `prepr("init")` function in the *Prepr Tracking Code* with the *googleTagManager* destination flag: ```js copy {4-8} prepr( "init", "abc123ecfff2385c9c4fe027d56ea7d544cee78b173", { destinations: { googleTagManager: true } } ); ``` Once this is enabled, Prepr automatically sends personalization events to *GTM dataLayer* under the name `prepr_personalize`. ```json copy { event: 'prepr_personalize', event_name: 'Impression', // or Click, Conversion, etc. prepr_experiment: 'experiment-id', prepr_item: 'content-item-id', prepr_variant: 'variant-id', prepr_segment: 'CUSTOMERS_FROM_GERMANY' // or 'ALL_OTHER_USERS' for control } ``` ## Additional configuration options You can optionally add the following options to the tracking pixel: ### variantImpressionThreshold This setting ensures that impression events for personalized variants are only triggered if the content stays in view for a minimum duration. This could help filter out accidental or too-short impressions, improving event quality ```js copy {4-6} prepr( "init", "abc123ecfff2385c9c4fe027d56ea7d544cee78b173", { variantImpressionThreshold: 2000 // in milliseconds (e.g., 2000 = 2 seconds) } ); ``` **Default**: 0 (fires always when a variant leaves the viewport) ### setCookieSecure This boolean setting allows you to flag the tracking pixel's cookies as secure when it's set to `true`. A secure cookie is only sent over encrypted connections, such as HTTPS. In other words, the true `setCookieSecure` setting instructs the browser to only include it in requests that use the `https:` protocol. ```js copy {4-6} prepr( "init", "abc123ecfff2385c9c4fe027d56ea7d544cee78b173", { setCookieSecure: true } ); ``` This prevents attackers from intercepting the cookie through eavesdropping on unencrypted HTTP connections. ## Excluding IP addresses Sometimes you want to make sure that internal IP addresses are not tracked. If you can exclude interactions from internal IP addresses, it makes the insights you gain more realistic and calculates more accurate metrics. You can exclude these IP addresses directly in Prepr. Follow the steps below to exclude IP addresses. 1. Click the icon and choose the **Event tracking** option to open the Event tracking page. ![exclude IP addresses](https://assets-site.prepr.io/6j34n0rhuvq1//prepr-tracking-code-example-exclude-ip-addresses.png) 2. Scroll down to the *Exclude IP addresses* section and enter the list of IP addresses that you want to exclude from data collection. Now that you've set up Prepr tracking, you can [record events](/data-collection/recording-events). Source: https://docs.prepr.io/data-collection/setting-up-the-tracking-code --- # Recording events *This guide walks you through how to record event data in Prepr.* ## Introduction Tracking how customers interact with your content is crucial for gaining insights and optimizing their experience. You can also track events to store customer characteristics when needed. You can easily track and send events to Prepr, such as views, likes, subscriptions, and custom events, directly from your front end. If you haven't yet done so, check out the [Fundamentals guide](/data-collection/fundamentals) for key data collection concepts. Before recording events, make sure you’ve already [enabled Prepr tracking in your web app](/data-collection/setting-up-the-tracking-code). ## Adding meta tags By adding meta tags to your front end, you can define the content items or identity provider customer IDs without needing to define them for every event you record. ### Tracking content items To start tracking events on your content items, add one of the following meta tags to the `` section on these content pages: Set the `content` value in the property or name tags to the *Item ID* of the content item, such as a *Home page*. ![content item ID](https://assets-site.prepr.io/5a748uth2dya//content-item-detail-page-copy-content-item-id.png) If Prepr tracking is set up and you've added a meta tag for specific content items, you can test this setup with the following steps: 1. Simply navigate to the page in your web app where you've included the meta tag above. This automatically triggers a view event that gets sent to Prepr. 2. Log in to your Prepr environment that your web app is connected to. 3. Go to the **Segments** tab. 4. Click the customer at the top of the list. The *Date* value will match the time that you opened the page. 5. On the customer detail page, you'll see a *View* event in the events table, and the details should match the content item that you added in the meta tag. ![view event](https://assets-site.prepr.io//xpcpa9smsa-view-event.png) Now, let's look at how to set up identity provider customer IDs for events. ### Tracking identity provider customer IDs As you've seen in the [fundamentals guide](/data-collection/fundamentals#anatomy-of-an-event), a customer is linked to an event. When tracking events using the tracking pixel, Prepr automatically links the event to a customer by generating a unique ID and storing it in the `__prepr_uid` cookie. This default behavior simplifies your code when recording events in Prepr. On the other hand, if your site uses an identity provider to manage your customers, you can add a meta tag to the HTML of your web app to link the customer ID to any event that occurs in the session. Replace the `content` value in the example code below with the known customer ID from your identity provider. ```html copy ``` If the `CUSTOMER_ID` you provide does not exist in Prepr when the event gets processed, a new customer profile will be created automatically. Now that you know how to link customers to events, let's look at how to record specific events. ### Tracking for multi-locale environments If you're running a multi-locale website, add the locale meta tag to indicate the locale you want to track. For example, to track A/B tests on text fields. ```html copy ``` ## Recording predefined events There are two types of predefined events you can record. - Customer events for specific content items to gain insights and optimize visitor experience. - Events to store customer characteristics for specific customers. Prepr recognizes each of the events below and processes them differently according to their purpose. ### View You can use this event type when you want to record when a customer opens a web page or when a customer scrolls to an element in a web page. If you want to record a view event for an entire page, [add the content item meta tag](#tracking-content-items) to the HTML in your page to automatically send the `View` event to Prepr when the page loads. If you want to record a view event for a content item embedded in a page, you can send the event using the following javascript function: ```js copy prepr('event', 'View', { 'id': "{{CONTENT_ITEM_ID}}" }); ``` See some example code below for when the customer moves their mouse over the footer. Replace the `{{CONTENT_ITEM_ID}}` with the *Content item ID* of the footer in this case. ### Like You can use the `Like` event to indicate when a customer clicks a link or button to indicate their approval or interest. Send a like event from your front-end with the following javascript function: ```js copy prepr('event', 'Like'); ``` See some example code below for when a customer clicks the **Like** button. If a `Like` event is sent to Prepr more than once, the subsequent events are simply ignored. If you want to indicate that a customer likes a specific content item in the page, you can send the relevant *Content item ID* in the event. ```js copy prepr('event', 'Like', { 'id': "{{CONTENT_ITEM_ID}}" }); ``` If you don't include a *Content Item ID* in the send request, the event will be linked to the content item in the [content item meta tag](#tracking-content-items) you set up earlier. You can also undo the `Like` event by sending a corresponding `Unlike` event for the same customer and content item. ```js copy prepr('event', 'Unlike'); ``` ### Bookmark You can use the `Bookmark` event to indicate when a customer clicks a link or button to save a piece of content to view later. Send a bookmark event from your front-end with the following javascript function: ```js copy prepr('event', 'Bookmark'); ``` See some example code below for when the customer clicks the **Bookmark** button. If a `Bookmark` event is sent to Prepr more than once, the subsequent events are simply ignored. If you want to indicate that a customer likes a specific content item in the page, you can send the relevant *Content item ID* in the event. ```js copy prepr('event', 'Bookmark', { 'id': "{{CONTENT_ITEM_ID}}" }); ``` If you don't include a *Content Item ID* in the send request, the event will be linked to the content item in the [content item meta tag](#tracking-content-items) you set up earlier. You can also remove the `Bookmark` event by sending a corresponding `Unbookmark` event for the same customer and content item. ```js copy prepr('event', 'Unbookmark'); ``` ### Subscribe You can use a `Subscribe` event to indicate when a customer clicks a link or button to subscribe to a newsletter, content updates, or other recurring content notifications. Send a subscribe event from your front-end with the following javascript function: ```js copy prepr('event', 'Subscribe'); ``` See some example code below for when the customer clicks the **Subscribe** button. If a `Subscribe` event is sent to Prepr more than once, the subsequent events are simply ignored. If you want to indicate that a customer likes a specific content item in the page, you can send the relevant *content item ID* in the event. ```js copy prepr('event', 'Subscribe', { 'id': "{{CONTENT_ITEM_ID}}" }); ``` If you don't include a *Content Item ID* in the send request, the event will be linked to the content item in the [content item meta tag](#tracking-content-items) you set up earlier. You can also cancel the `Subscribe` event by sending a corresponding `Unsubscribe` event for the same customer and content item. ```js copy prepr('event', 'Unsubscribe'); ``` ### SignUp You can use a `SignUp` event to track when a customer creates a new account or registers on your web app. This event is not related to a specific content item, but to a specific customer. In this case, make sure to [add the customer meta tag](#tracking-content-items). Send a `SignUp`event from your front-end with the following javascript function: ```js copy prepr('event', 'SignUp'); ``` See some example code below for when the customer clicks the **Sign Up** button. If a `SignUp` event is sent to Prepr more than once, the subsequent events are simply ignored. Unregistered customers are automatically deleted from Prepr after 90 days of inactivity. The `SignUp` event ensures the customers who've signed up will not be deleted. ### Tag Similar to the events listed above, you can also trigger customers to volunteer data about themselves through your web app. This could be characteristics like their job title or industry they work in. Knowing if a customer is a developer, for example, can help you direct them to more technical content. For example, when a customer fills a specific value in a form on your page, you can send the entered value as a `Tag` on the customer profile. Use the javascript function below to store a tag for the customer, for example, to indicate that they are a health care worker. ```js copy prepr('event', 'Tag', ['healthcareworker']); ``` In the example code below we send a `Tag` to indicate when the customer chooses a job title from a dropdown field. ### Email Similar to the `Tag` event above, you can trigger an event to store the email address of a customer. For example, when a customer fills in a form on your page, you can add the entered email address to the customer profile. This makes it easier to track the customer events in other platforms you might be using. Use the javascript function below to store the email address for the customer. ```js copy prepr('event', 'Email', 'jesse.ward@acme-company.com'); ``` ## Recording custom events You can enhance your A/B tests and adaptive content by setting up custom events in your web app. For example, if you want to track when a visitor makes a `Purchase` or clicks to `Start` a video or livestream. Before recording custom events, take note of the following rules when naming your custom events. ### Naming rules You can choose any name for the custom event that meets the naming rules below. - Start the name with a capital letter. - The name has to be one word. In other words, no spaces. - Don't include any special characters like %, ˆ, &, etc. - The name should not start with a number. - The name cannot be any of the following reserved terms: `View`, `Like`, `Bookmark`, `Subscribe`, `SignUp`, `Tag`, `Email`, `Merge` Depending on the purpose of your custom events, these can be recorded in Prepr in different ways: ### Define conversion metrics You can use custom events to set up conversions in your web app to get more valuable metrics for A/B tests or adaptive content. To do this, simply [add HTML attributes to your A/B tests](/ab-testing/setting-up-ab-testing#add-html-attributes-to-track-impressions-and-conversion-events) or [when you set up personalization](/personalization/setting-up-personalization#add-html-attributes-to-track-impressions-and-conversion-events). By adding these HTML attributes, these custom events are automatically stored in Prepr. Once done, you can also define customer segments using these custom events. ### Record custom events If you need to record custom events for [customer segments](/personalization/managing-segments) or [goals](/personalization/defining-goals), for instance, you can send a *Custom event* with the `event` method. If you've already [used custom events to define conversions](#defining-conversion-metrics), then you don't need to add the below javascript function. ```js copy prepr('event', '{{CUSTOM_EVENT_NAME}}'); ``` In the example code below we send a `Purchase` event when a customer completes a purchase in the web app. ## Sending events to Google Tag Manager (GTM) To send experiment-related events (such as impressions of content variants, A/B experiments, or segmented views) to Google Tag Manager, you can enable the built-in GTM integration in the [Prepr Tracking Code](#adding-the-tracking-code). This allows you to reuse the data collected by Prepr for reporting and personalization pipelines in Google Analytics 4 (GA4) or other GTM-connected services. To activate this, you simply need to update your `prepr("init")` function in the *Prepr Tracking Code* with the *googleTagManager* destination flag: ```js copy {4-8} prepr( "init", "abc123ecfff2385c9c4fe027d56ea7d544cee78b173", { destinations: { googleTagManager: true } } ); ``` Once this is enabled, Prepr automatically sends personalization events to *GTM dataLayer* under the name `prepr_personalize`. ```json copy { event: 'prepr_personalize', event_name: 'Impression', // or Click, Conversion, etc. prepr_experiment: 'experiment-id', prepr_item: 'content-item-id', prepr_variant: 'variant-id', prepr_segment: 'CUSTOMERS_FROM_GERMANY' // or 'ALL_OTHER_USERS' for control } ``` ## Using identify providers When a customer signs in to your website or app and you want to add the user ID from the relevant Identity Provider to the customer profile in Prepr you can call the `Identify` event. Use the javascript function below to store the external ID for the customer. If a customer already exists with this external ID, the profiles will be merged. ```js copy prepr('event', 'Identify', 'external-profile-ID'); ``` ## Maximum events per customer Source: https://docs.prepr.io/data-collection/recording-events --- # Tracking data using the REST API *This guide walks you through tracking data in Prepr using the REST API instead of using the Prepr tracking pixel.* ## Introduction You can track and capture data to understand how customers engage with your content. This is an essential step when setting up personalization, A/B testing and recommendations. Even before implementing personalization, it also helps your digital teams gather useful insights for [segmentation](/personalization/managing-segments). [Setting up Prepr tracking](/data-collection/setting-up-the-tracking-code) is a simple way to track data in Prepr. If you're unable to enable the Prepr tracking pixel, for example, due to restrictions, you can record events in Prepr by using the REST API instead. If you haven't already done so, check out the [fundamentals data collection guide](/data-collection/fundamentals) to understand key concepts. Once you have a good understanding, let's dive into recording events using the REST API. ## Recording events using the REST API With the REST API you can send event data to Prepr. This can be convenient for offline conversions or if you're working in a restricted environment and aren't allowed to load third-party Javascript snippets. ### JSON Structure The table below shows the fields that are supported in the REST API. | argument | type | required | description | |-----------------------|-------------|----------|-----------------------------------------------------------------------| | `label` | String | Yes | Defines the event type. | | `timestamp` | UNIX Timestamp | | Event timestamp (default time of request). | | **Customer Data** | | | | | `customer` | Array | Yes | | | `customer.id` | String | | ID of Prepr User, your own customer ID or the customers email address | | **Content Item Data** | | | | | `content_item` | Array | | | | `content_item.id` | String | | Content item ID the event is recorded for. | | `content_item.locale` | String | | Locale like `en-GB`. | | **Metadata** | | | | | `utm_medium` | String | | Campaign Medium | | `utm_source` | String | | Campaign Source | | `utm_campaign` | String | | Campaign Name | | `utm_term` | String | | Campaign Term | | `utm_content` | String | | Campaign Content | | `rl` | String | | Referrer location, example: `https://prepr.io/` | You need to supply a customer ID for the event to be recorded. If the customer ID is not found in your customers list when the event gets processed, a new customer will be created. ### Recording events If you collected all the data, the JSON data object should be posted to the following endpoint: `POST https://tracking.prepr.io/events` ```json copy { "label" : "View", "customer" : { "id" : "x-21381723243-PRP" }, "timestamp" : 1609588800, // Optional "content_item" : { // Optional for custom events "id" : "76a5e261-ec2a-4bd2-8195-cf7e889b0a68" } } ``` **Request headers** - This endpoint requires an HTTP Authorization header with an Access Token containing the `capture_publish` scope. - Include the `Prepr-Visitor-IP` header to set the location in the customer profile to the visitor's actual location. If the event was successfully queued the endpoint will return a status code `202 Accepted`. To validate your input, within a few seconds, you'll see the data reflected in the Prepr **Segments** page. ## Adding a tag For example, when a customer fills a specific value in a form on your page, you can send the entered value as a `Tag` on the customer profile. Use the request below to store a tag for the customer, for example, to indicate that they are a health care worker. In the example code below we send a `Tag` to indicate when the customer chooses a job title from a dropdown field. `POST https://tracking.prepr.io/events` ```json copy { "label" : "Tag", "customer" : { "id" : "x-21381723243-PRP" }, "tags": [ "healthcareworker" ] } ``` ## Adding an email address When you want to save the customer's email address in their profile, you can send the entered value with the `Email` label. See the example request below on how to send and store an email address in the customer profile. `POST https://tracking.prepr.io/events` ```json copy { "label" : "Email", "customer" : { "id" : "Adf2e64cc-1e98-4fa1-81b9-12341f88dd88" }, "email" : "jesse.ward@acme-company.com" } ``` Source: https://docs.prepr.io/data-collection/tracking-data-using-the-api --- # Managing customer data manually *This guide explains how to perform different actions on customer data directly in Prepr.* ## Introduction Customers in Prepr are your web app visitors, both anonymous and known, who interact with your web app. When you store customer profiles in Prepr, you can track their interactions to understand common characteristics and behavior. This allows you to personalize their experiences by grouping them into *Segments*. For more details, check out the [*Managing segments guide*](/personalization/managing-segments). Manage customers in Prepr by adding, updating, merging, exporting, anonymizing, and deleting customer profiles. ## Adding customer profiles You can add customer profiles in Prepr automatically or manually. When you [enable Prepr tracking in your web app](/data-collection/setting-up-the-tracking-code) to collect customer data, profiles are automatically created in the system for each web app visitor, if they don't already exist, Alternatively, you can also add customer profiles manually in two ways. ![Add customer](https://assets-site.prepr.io//6nfq4xhh4w14-add-customer-profile.png) ### Importing customer profiles To manually import multiple customers into Prepr follow the steps below. 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left, then click the **Add customer** dropdown and choose **Import customers** to upload a CSV file. ![import customers modal](https://assets-site.prepr.io//yynlkpaxmkt-import-customer-profiles.png) 3. Use the table below to create the complete CSV file. | Column title | Variable | Format | |:-----------------------|:---------------------|:-----------------------------------------------------------------------| | first\_name | First name | | | last\_name | Last name | | | email | Email address | Valid email address | | country | Country | Only English notation allowed | | tags | Tags | Comma-separated | | reference\_id | Reference | Only alphanumeric characters allowed. | After the import, you will receive an email with a summary of the following information: - How many new customers have been created - How many existing customers have been updated with new information - How many customers were already fully present in the database - How many rows were imported (and how many failed, reason included) ### Adding a single customer profile To manually add one customer profile, follow the steps below: 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left, then click the **Add customer** button to create one profile. 3. Enter the *First name* and *Last name*, if needed, and click the **Save** button. ## Updating customer profiles To update a single customer profile, follow the steps below: 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left. Use the *Search* or *Filter* to find the customer that you want to update. 3. Click the customer and click the **Edit details** button to enter values for the *Country* and *Tags*. ![Edit customer](https://assets-site.prepr.io//2gy9kt16n6kp-add-customer-manually.png) To update multiple customer profiles, [import them with matching email addresses](#add-customer-profiles) or [use the mutation API](https://docs.prepr.io/mutation-api/customers-create-update-and-destroy). ## Merging customer profiles A good customer database is a tidy database. This means that profiles are enriched with the correct customer data and any duplicates are removed. You can easily merge customer profiles in Prepr. In other words, you can combine duplicate profiles, where one profile contains certain data and the second profile contains other data about the same person. To merge two profiles, follow the steps below. 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left. Use the *Search* or *Filter* to find the customer that you want to merge. And click the **Merge** button to open the merge modal. ![merge modal](https://assets-site.prepr.io//1mgf6uchxgfh-merge-customer-profile.png) 3. Search for the customer whose data you want to merge and click the **Merge** button. When two customer profiles are successfully merged, the fields will be updated as follows: - All fields of which only one is allowed (such as name, or date of birth) are filled in if they are empty in the main profile. - All fields of which more than one is allowed (such as events, email addresses, or telephone numbers) are added to the main profile. ## Exporting customer profiles Prepr offers two types of customer exports: export of a single customer profile (for GDPR purposes) and a bulk export via CSV. Use the *GDPR export* to give individuals the right to request a copy of any of their personal data which are being used in any way according to the *General Data Protection Regulation*. 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left. Use the *Search* or *Filter* to find the customer that you want to export. Hover over the customer to the right and choose the **GDPR Export** option. A Json file for this customer will be directly downloaded to your local device. Use the *CSV export* to export the Prepr customer list to a CSV file. 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left. Click the **Export** button to open the export modal. ![Export customers](https://assets-site.prepr.io//f5vu96zizfq-export-customer-profiles.png) 3. Choose the fields that you want included in the export and click **Export**. We'll process your request and send you an email when it's ready to download. The customer export is only available for user roles with [bulk export permissions](/project-setup/managing-roles-and-permissions#add-or-edit-roles). ## Deleting customer profiles You can delete customer profiles in a couple ways: - **Select multiple customers from the Customers list** 1. Go to the **Segments** tab. 2. Hover over and click the checkbox for the customers you want to delete. 3. To select all customers, click the icon at the top of the list. 4. Click the icon at the top of the list to delete all the selected customers. 5. In the pop-up window, click **Delete** again to confirm the action. - **Select single customer from the Customers list** 1. Go to the **Segments** tab. 2. Hover over the customer you want to delete to make the actions available. ![highlighted customer](https://assets-site.prepr.io//7ca1z4njo5hf-delete-single-customer-from-customer-list.png) 3. Click the icon on the right to delete the highlighted customer. 4. In the pop-up window, click **Delete** again to confirm the action. - **From the Customer page** 1. Go to the **Segments** tab. 2. Click the **All customers** link on the left. Use the *Search* or *Filter* to find the customer that you want to delete. 3. Click the customer to open the *Customer* page and click the **Delete** button. 4. In the pop-up window, click **Delete** again to confirm the action. Source: https://docs.prepr.io/data-collection/managing-customer-data-manually --- # Privacy & Security *The General Data Protection Regulation (GDPR) is the European Union’s legal framework for protecting personal data. It defines how organizations must collect, process, store, and delete personal information, and gives individuals specific rights over their data.* ## Roles and responsibilities Before getting into the practicalities for ensuring GDPR compliance, it's important to understand the key roles and responsibilities when using Prepr CMS to process personal data of web app visitors. ### Controller Under the GDPR, you, as our customer, have the role of the controller. This means, you decide which personal data is collected, why it's collected, and how long it's retained. As the controller, you must ensure that there is a lawful basis for processing and that all data subject rights can be fulfilled. ### Processor We, as Prepr, perform the role of the processor. We process personal data only according to your documented instructions and we don't decide the purposes of processing. As a processor, we implement appropriate technical and organizational measures, ensure confidentiality, work only with vetted sub-processors, and support you in fulfilling GDPR obligations. ## Complying with GDPR Now that you understand your GDPR responsibilities when using Prepr CMS, follow the practical steps below to stay compliant. Now that you know what's required, here are the Prepr tools and features to help you stay compliant. ## Using Prepr to process personal data You can process personal data directly in Prepr via the UI, make [REST API requests](/mutation-api/customers) to fetch or update customers, and track visitors using the [tracking pixel](/data-collection/setting-up-the-tracking-code) or the [Rest API](/data-collection/tracking-data-using-the-api). ### Best practices Before we look at specific features and tools, here are some best practices to follow. #### Default data set You should only collect what is strictly necessary for your web app to function or for your specific business goal. - Prepr tracking pixel: Prepr uses client-side data collection through a first-party tracking pixel. This ensures data accuracy and bypasses most ad-blockers. - Additional data: If a piece of data doesn't have a clear, documented purpose, do not collect it. #### Retention periods By default, we delete inactive customers after 90 days. You can send a [*SignUp* event](/data-collection/recording-events#signup) to make sure that customers who’ve signed up to your web app will not be deleted. #### Important restrictions - No sensitive personal data: We strongly recommend against storing the following in the CMS: - Financial information like credit card details or bank account numbers. - Health or medical information. - Racial or ethnic origin. - Political opinions or religious beliefs. - Biometric or genetic data. - No personal data in *Assets*: Don't store personal data inside uploaded assets (like images, or PDFs). Now that we've covered these ground rules, let's look at some features and tools we provide to help you manage these responsibilities effectively. ### Right of Access: Exporting customer data To support the *Right of Access*, if customers request to access their personal data, you can either use the Prepr UI or the the Rest API to export customer data. To export a a single customer profile directly in Prepr, follow the steps below. ![GDPR export](https://assets-site.prepr.io/36r1cr8j4d71//gdpr-export.png) 1. Open the **Segments** tab to see *All customers*. 2. You can search for the customer profile by their *ID*, *email*, or *reference ID* 3. Hover over the customer and click the icon to start the GDPR export. A JSON file containing the full customer record with the following details is downloaded. - personal details - full address - email address - events (such as likes, views, bookmarks) - tags This export can be shared with the customer as part of a GDPR access request. ### Right to Erasure: Deleting customer data The right to erasure, also known as the “Right to be forgotten,” allows individuals to request the complete deletion of their personal data. To delete a customer directly in Prepr, follow the steps below. ![Deleting a customer](https://assets-site.prepr.io/1kwu7d612xwu//deleting-a-customer.png) 1. Open the **Segments** tab to see *All customers*. 2. You can search for the customer profile by their *ID*, *email*, or *reference ID* 3. Hover over the customer and click the icon to delete the customer. All personal data for this customer is deleted immediately once you click the **Yes, delete** button to confirm. This deletion is irreversible and removes the customer’s profile, events, and all associated personal data from Prepr CMS. ### Right to Rectification: Updating customer data The right to rectification allows individuals to have inaccurate or outdated personal data corrected. To update a customer’s information directly in Prepr, follow the steps below. ![Updating a customer](https://assets-site.prepr.io/27c46507h0ss//updating-a-customer.png) 1. Open the **Segments** tab to see *All customers*. 2. You can search for the customer profile by their *ID*, *email*, or *reference ID* 3. Click the customer to open the profile and click the **Edit details** button. 4. Update the relevant fields, such as name, email address, or other personal details. 5. Click the **Save** button to save the changes. The corrected data is applied immediately and reflected across all systems that rely on Prepr. ### Right to Data Portability The *Right to Data Portability* allows individuals to obtain their personal data and reuse it for their own purposes across different services. As described in the [*Right of Access*](#right-of-access-exporting-customer-data) section, you can simply use the *GDPR export* feature directly in Prepr. ## How we comply with GDPR We support GDPR compliance by implementing strong operational, security, and privacy measures as a processor. These include: ### Processing instructions only We process data exclusively based on the your configured settings and documented instructions. ### Data security You can find detailed information on how we ensure data security with technical and organizational measures [in our trust hub](https://prepr.io/security-and-compliance). At a high level, this information includes the following points. - Encryption at rest and in transit - Access controls, such as SSO - Logging and monitoring - Secure infrastructure - Backup and disaster recovery - Regular security testing ### Sub-processors We provide the following information on our [sub-processors](https://prepr.io/company/sub-processors). - a list of sub-processors - their roles and data categories - links to their compliance policy ### EU data residency We store and process all personal data inside the EU unless you explicitly approve otherwise. ### Data breach notification We notify you without undue delay (target 48 hours) if any personal data breach occurs. As an *Enterprise* service level customer, we're happy to make custom arrangements with you. ### GDPR assistance We support you by forwarding DSAR requests, helping with DPIAs where needed, and if you're an *Enterprise* service level customer, we also provide documentation for audits and compliance checks. ### End-of-contract data handling We ensure the deletion or return of all personal data upon termination of the agreement. Through these measures, we ensure all processing performed on your behalf meets GDPR requirements and follows the contractual obligations in the data processing agreement. Source: https://docs.prepr.io/data-collection/privacy-and-security --- # How bots impact event data ## What are bots? A search bot, sometimes called a spider, is a robot that continuously browses the internet, usually for the purpose of building a search index or archiving websites. Bots can either run on servers in a datacenter such as Amazon Web Services, or sometimes, on people’s personal computers that have been infected with malware or a virus (referred to as a botnet). Some bots, such as GoogleBot, are used for legitimate purposes such as indexing the web. Bots can artificially inflate event data, so it’s important to be aware of their existence. ## Prepr and search bots Prepr can detect search bots that deliberately reveal themselves. All traffic from known bots and spiders is automatically excluded. This ensures that your Prepr data, to the extent possible, does not include events from known bots. At this time, you cannot disable known bot data exclusion or see how much known bot data was excluded. Known bot traffic is identified using a combination of our research and the International Spiders and Bots List. ## List of excluded bots Below is a list of search bots and their user-agents that Prepr identifies. | user Agent | Search Bot | |-----------------------|-----------------------| | 200pleasebot | 200PleaseBot | 360spider | 360Spider | abot | CrawlDaddy, abot | addthis | AddThis | adldxbot | Microsoft Bing Ads | admantx | ADmantX Platform Semantic Analyzer | adsbot-google | Google Adwords | advbot | AdvBot | ahrefsbot | Ahrefs backlinks research tool | alexa | Alexa Crawler | apache-httpclient | Java http library | apachebench | ApacheBench (ab) | apis-google | APIs-Google | appengine-google | Google App Engine | applebot | Apple Bot | archive.org\_bot | Internet Archive (archive.org) | ask jeeves | Ask Jeeves | asynchttpclient | Java http and WebSocket client library | awe.sm | Awe.sm URL expander | baidu | Baidu | bdcbot | Big Data Corp | bingbot | Microsoft Bing | bingpreview | Microsoft Bing preview | bitlybot | bit.ly bot | blekkobot | Blekkobot | blexbot | BLEXBot (webmeup) | bot@linkfluence.net | Linkfluence bot | bufferbot | BufferBot | buibui-checkbot | buibui | butterfly | Topsy Labs | buzztalk | buzztalk | catchbot | CatchBot (catchbot.com) | check\_http | Nagios monitor | cliqzbot | Cliqzbot | cmradar/0.1 | CMRadar/0.1 | coldfusion | ColdFusion http library | commoncrawl | CCBot | comodo-webinspector-crawler | Comodo | crowsnest | Crowsnest | curabot | cura.yt | curl | curl unix CLI http client | dap/nethttp | DAP/NetHTTP | datagnionbot | datagnion.com/bot.html | daumoa | Korean portal and search engine indexing bot | developers.google.com/+/web/snippet | Google Plus | diffbot | Diffbot | digitalpersona fingerprint software | HP Fingerprint scanner | domain re-animator bot | Domain Re-Animator Bot | domainsbot | DomainsBot | domaintunocrawler | DomainTuno | dotbot | Dot Bot | duckduck | Duck Duck Go | elb-healthchecker | AWS ELB HealthChecker | embedly | Embedly | eoaagent | EOAAgent | eventmachine httpclient | Ruby http library | everyonesocialbot | EveryoneSocial | evrinid | Evri bot | exabot | Exalead's bot | exaleadcloudview | ExaleadCloudView | facebookexternalhit | Facebook Bot | facebot | Facebook Bot | feedburner | RSS bot | feedfetcher-google | Google Feedfetcher | findxbot | Findxbot | flipboardproxy | FlipboardProxy | friendfeedbot | FriendFeed | genieo | Genieo Web filter bot | getprismatic.com | getprismatic.com | gigabot | Gigabot spider | gimme60bot | Gimme60 (gimme60.com) | gimmeusabot | Gimme60 (gimme60.com) | go http package | Go http library | google page speed insights | Google Page Speed Insights | google Web Preview | Google Instant Previews crawler | google-structured-data-testing-tool | Google-StructuredDataTestingTool | google-structureddatatestingtool | Google-StructuredDataTestingTool | googlebot | Google Bot | googlestackdrivermonitoring-uptimechecks | GoogleStackdriverMonitoring-UptimeChecks | grapeshotcrawler | GrapeshotCrawler | gravitybot | Gravity Bot | hatena::bookmark | Hatena::Bookmark | heritrix | heritrix | htmlparser | HTMLParser | http\_request2 | HTTP\_Request2 | httpclient | HTTPClient | https://developers.google.com/+/web/snippet | Google+ Snippet Fetcher | hubspot | HubSpot | ia\_archiver | Internet Archive (WayBackMachine) | icoreservice | iCoreService | idmarch | idmarch.org/bot.html | inagist | URL resolver | insieve | Insieve Bot | insitesbot | Insitesbot | instapaper | Instapaper | istellabot | IstellaBot | jack | jack | jakarta commons | Jakarta Commons HttpClient | java | Generic Java http library | jetslide | Jetslide | js-kit | URL resolver | kemvibot | Kemvi | kimengi | Kimengi Bot | knows.is | knows.is | kojitsubot | Kojitsubot | komodiabot | KomodiaBot | kraken | kraken | laconica | Laconica | libwww-perl | Perl client-server library | lijit crawler | Lijit | linkdexbot | Linkdex Bot | linkedinbot | LinkedIn | linkscrawler | LinksCrawler | linode | Linode Longview | lipperhey | Lipperhey | livelapbot | Livelapbot | loadtimebot | Load Time Bot | longurl | URL expander service | ltx71 | ltx71.com | lumibot | Lumibot | lwp-trivial | Another Perl library | magpie-crawler | magpie-crawler | mail.ru\_bot | Mail.ru Bot | meanpathbot | meanpath | mediapartners-google | Google Adsense bot | megaindex.ru | MegaIndex | memorybot | mignify.com/bot.html | metauri | MetaURI | mfe\_expand | Mcafee spider | mir web crawler | MIR web crawler | mj12bot | Majestic-12 spider | mojeekbot | Mojeek UK search crawler | mrchrome | MrChrome | ms search 6.0 robot | MS Search 6.0 Robot | msnbot-media | Microsoft media bot | msnbot | Microsoft bot | nerdybot | NerdyBot | netcraft | Netcraft | netstate | netEstate NE Crawler | netvibes | Personalized dashboard bot | netzcheckbot | netzcheck | newrelicmonitor | NewRelic monitor | newrelicpinger | NewRelicPinger | newsme | newsme | niki-bot | niki-bot | ning | NING | Yet Another Twitter Swarmer | nutch | Apache search spider | openhosebot | OpenHoseBot | orangebot | OrangeBot | pagesinventory | pagesinventory.com | panopta | Monitoring service | paperlibot | PaperLi | peerindex | peerindex | percolatecrawler | PercolateCrawler | perfectmarketkwtbot | PerfectMarket | phantomjs | PhantomJS | pingdom | Pingdom monitoring | pinterest | Pinterest | plukkie | botje.com/plukkie.htm | privacyawarebot | PrivacyAwareBot | proximic | Proximic Spider | psbot-page | Picsearch | publiclibraryarchive.org | publiclibraryarchive.org | pycurl | Python http library | python-httplib2 | Python-httplib2 | python-requests | Python http library | python-urllib | Python http library | queryseeker | QuerySeekerSpider | quicklook | QuickLook | re-animator | Domain Re-Animator Bot | readability | Readability | rebelmouse | RebelMouse | redditbot | Reddit Bot | relateiq | RelateIQ | riddler | Riddler Bot | rogerbot | SeoMoz spider | rssmicro | RSS/Atom Feed Robot (rssmicro.com) | ruby | Ruby | scrapy | Scrapy | screaming frog seo spider | Screaming Frog SEO Spider | searchmetricsbot | SearchmetricsBot | semrushbot | SEO analysis bot | seokicks | SEOKicks | seznambot | SeznamBot | shopwiki | ShopWiki | shortlinktranslate | Link shortener | showyoubot | Showyou iOS app spider | siege | Joe Dog Siege | sistrix | SISTRIX | siteuptime | Site monitoring services | slack | Slackbot-LinkExpanding | slackbot | Slack Bot | slurp | Yahoo spider | smtbot | SimilarTech | socialrank | SocialRankIOBot | sogou | Chinese search engine | spbot | OpenLinkProfiler | spider | generic web spider | spinn3r | Spinn3r aggregator | sputnikbot | SputnikBot | squider | Squider | statuscake | StatusCake | stripe | Stripe | test certificate info | C http library? | tineye | TinEye Bot | traackr | Traackr Bot | trendictionbot | Trendiction Search | turnitinbot | TurnitinBot | tweetedtimes | The Tweeted Times | tweetmemebot | TweetMeMe Crawler | twikle | Social web search bot | twitjobsearch | TwitJobSearch | twitmunin | Twitmunin | twitterbot | Twitter URL expander | twurly | Twurly | typhoeus | Typhoeus | umbot | uberMetrics | unwindfetch | Gnip | uptimerobot | Uptime Robot | vagabondo | Vagabondo | vb project | Visual Basic | vigil | Vigil | vkshare | VKontake Sharer | voilabot | VoilaBot | vrcrawler | Venture Radar | wasalive-bot | Wasalive Bots | watchsumo | WatchSumo | wbsearchbot | Ware Bay Best Buys | webscout | Webscout | wesee | WeSEE | wget | wget unix CLI http client | wordpress | WordPress spider | wormly | WormlyBot | wotbox | Wotbox | xenu link sleuth | Xenu Link Sleuth | xing-contenttabreceiver | Xing bot | xovibot | XoviBot | yacybot | YaCy | yahoo-ad-monitoring | Yahoo Ad monitoring | yandex | Yandex | yeti | Naver Corp | yourls | YOURLS | zelist.ro | feed parser | zibb | ZIBB spider | zitebot | Zite | zyborg | Zyborg Source: https://docs.prepr.io/data-collection/search-bots --- # Setting up personalization *Estimated duration: 15-30 minutes* *This guide demonstrates how to set up personalization and the related metrics in your web application using the Prepr GraphQL API.* ## Introduction Prepr lets you create personalized experiences with *Adaptive content*. With *Adaptive content*, content editors can make different versions of content for various visitor segments. You can then show the right content to each visitor based on their segment giving them a personalized experience. By doing the one-time setup detailed below, Prepr can track and measure the visitor interactions for each adaptive content element. ## Use case Let's look at an everyday use case. The marketing team wants to increase conversions for their car leasing website. They've decided to group their customers by those who want to lease electric cars. Based on this segment they add adaptive content to the home page to target these customers. **General website visitors** When customers navigate to the Acme Lease home page, they see a generic page like in the image below. ![Acme lease home page](https://assets-site.prepr.io/p6rja5r1cj8//dynamic-website-with-prepr-content.png) **Visitors interested in leasing an electric car** When a potential customer searches for an electric lease car and clicks an Acme Lease ad, they are directed to the electric lease landing page on the Acme Lease website. If they visit the home page again later, they'll see content focused on electric lease cars instead of the generic home page above. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) For this use case, the front-end application is set up to track each visitor's behavior based on their interests. When they view the *Electric Lease Landing Page*, Prepr places them in the *Electric Car Buyers* segment. The marketing team can then evaluate metrics in Prepr to measure conversions based on their goals for the adaptive content and determine how well the content performs. ## Prerequisites To implement adaptive content for the above example, you need to have the following set up in Prepr: - [A Prepr CMS account](https://signup.prepr.io/?plan=free) ![Home page content item](https://assets-site.prepr.io/3kzih4y0123a//acme-lease-homepage-adaptive-content-hero-and-feature-sections.png) ## Set up personalization in your front end Before setting up personalization in your front end, make sure the following items are in place: - [Segments](/personalization/managing-segments#create-segments-based-on-prepr-data). If you've loaded the Acme Lease demo content, then the *Electric Car Buyers* segment is available with a condition to check when the Electric lease landing page is viewed. - [Enable Prepr tracking](/data-collection/setting-up-the-tracking-code) and [add the content item meta tag](/data-collection/recording-events#tracking-content-items) to track visitors when they view pages. Now you're ready to set up personalization in the following steps: 1. Create a customer ID to track and link each visitor to a variant. 2. Retrieve adaptive content using the API. 3. Track impressions and conversions. ## Other use cases Other than segments based on visitor behavior, you can set up personalization for other criteria. ### Segments from external CRM/CDP systems It's possible to set up adaptive content based on segments maintained in other CDP/CRM systems. In this case, you need to reference these external segments from within Prepr using the segment unique identifier from that system. To set up personalization for external segments, follow the steps below. 1. [Create a new segment in Prepr](/personalization/managing-segments#use-external-segments-from-crmcdp-systems) and set the *ID* value to the segment unique identifier copied from your CRM/CDP system. 2. [Retrieve adaptive content using the API](#retrieve-adaptive-content-using-the-api) with one difference — pass the `Prepr-Segments` header instead of the `Prepr-Customer-Id`. For more information, refer to our [API documentation](/graphql-api/personalization-recommendations-personalized-stack). 3. If the segment is based on external customer data, ensure that your front end is connected to the external CRM/CDP system for data retrieval. ## Want to learn more? Check out the following chapters: - [Capturing event data](/data-collection/step-by-step-guide) - [A/B testing](/ab-testing/setting-up-ab-testing) - [Recommendations](/recommendations) - [Connecting your front-end application](/connecting-a-front-end-framework) ## Schedule a free consultation Do you want to get started with adaptive content 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/personalization/setting-up-personalization --- # Defining goals for adaptive content and A/B testing *This guide covers everything you need to know about defining conversion goals to measure in-depth engagement based on adaptive content or A/B test content.* ## Introduction A conversion goal is a specific, measurable action that you, as a marketer, want a web app visitor to take. It represents a step forward in the customer journey that aligns directly with your business objectives. Let's take a look at a use case. You want to increase the number of visitors who request a quote through your car leasing website. To achieve this goal, you take the following actions: 1. You find that the *Homepage* is one of the main entry points in the customer journey that results in a visitor requesting a quote. ![Home page customer journey](https://downloads-site.prepr.io/3volgjiwvqj6-home-page-customer-journey.gif) 2. So, you come up with a plan to improve the content in the hero section of the *Homepage*. - You decide to group customers by those who want to lease electric cars. - You prepare personalized content for this targeted audience to drive more visitors toward the goal of requesting a quote. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) 3. To determine how well this personalized variant of the Hero section performs, you add it as adaptive content with the following goals: - Micro-conversion goal: You want to measure how many customers click the **Find your car** button on the home page because it's the start of the customer journey to reach the end goal. - Macro-conversion goal: You want to measure how many customers request a quote within a day of visiting the home page. Let's dive into how to define goals in Prepr. ## Defining conversion goals You typically define conversion goals in the context of adaptive content (personalization) or A/B tests. Let's define goals based on the use case above. 1. Go to **Segments → Goals**. 2. Click the **+ Add goal** link and set a condition like in the example below. ![Goal definition](https://assets-site.prepr.io/71wpirc8sycj//example-primary-goal.png) You can set up any combination of conditions in your goals for customer [*Events*](#events). Combine conditions by using the `AND` or `OR` logical operators. 3. Click the **Save** button and provide a meaningful name for the goal. 4. Click the **Save** button. Now that you've seen how to define a goal, let's look at the filter options in more detail to help you set up all kinds of conditions. ![Goal events](https://assets-site.prepr.io/jptrtm6nuxx//goal-events-list.png) When you set up conditions to define goals, you can choose an action related to *Events*. Customer events refer to how the customer interacted with content items rendered by your web app, such as **Viewed**, **Liked**, **Clicked**, **Bookmarked**, and **Subscribed**. You can also choose a **Custom event** for any other event specific to your metrics needs. These [events need to be recorded](/data-collection/recording-events) in the front end to track and measure these conversions accurately. **Content item selection** When you use one of the non-custom events, you can then choose from the following list of options to define the set of content items that you want to include in the condition. - *Any item* - The default option. Include customers who performed events on any content item. - *Specific items* - Only include customers with events on one or more specific content items. Choose the content item by its *Title* for this option. For example, *Customers who* `did` `view` `specific items` `Landing Page Electric Car` `at least once`. - *Items of a model* - Only include customers with events on content items for this model. For example, *Customers who* `did` `view` `items of a model` `Article` `at least once`. - *Items with specific tags* - Only include customers with events on content items with one or more tags. For example, *Customers who* `did` `view` `items with specific tags` `Article` `at least once`. - *Items with specific reference to item* - Only include customers with events on content items linked to specific content items. For example, *Customers who* `did` `view` `items with a reference to` `John Smith` `at least once` can group customers who viewed articles written by the person, *John Smith*. When adding a new condition for an event, the `did` action is selected by default. You can also choose the `did not` action, instead. For example, *Customers who* `did not` `view` `items of a model` `Article` `at least once` `in the last quarter`. **Frequency options** You can further narrow your condition by specifying how many times an event occurred. Use one of the following options: - *At least once* - The default value. - *x number of times* - The event must occur exactly *x* times where *x* is a whole number. - *More than x times* - Only include events that happened more than *x* times where *x* is a whole number. - *Less than x times* - Only include events that happened less than *x* times where *x* is a whole number. **Time filter** You can the narrow your condition to only include customers with recent activity (*Events*) by specifying when last the customer interacted with a content item. You can choose from one of the time filters below. - *In the last day* - *In the last week* - *In the last month* - *In the last quarter* (The default value) Once, you're satisfied that your goals are well-defined, you can then link them to your adaptive content or A/B test. ## Link goals to experiments You can link goals to either [adaptive content](/personalization/managing-adaptive-content#add-an-adaptive-content-element) or [A/B test experiments](/ab-testing/running-ab-tests#add-the-ab-test-to-a-stack-element). If you already have adaptive content or A/B test in your content items, follow the steps below to link the relevant goals. 1. Go to the **Content** tab, and click to open the content item with adaptive content or an A/B test. 2. Go to the adaptive content or A/B test block and click the icon in the block and choose the **Manage settings** option. ![settings example](https://assets-site.prepr.io/4qatxvs6a2q5//adaptive-content-settings.png) 3. Set the **Primary goal** value to the goal you previously defined (usually for a macro-conversion). 4. Set the **Secondary goals** value to another goal (usually for a micro-conversion). 5. Keep the default **Time window** of *1 day*, for example to measure the number of visitors achieved the goal within one day of viewing the A/B test content or adaptive content. Now that you've linked the goal, Prepr can calculate metrics for that goal. ![Example metrics with goals](https://assets-site.prepr.io/687jpedowhbj//metrics-request-a-quote-example.png) ## What’s next? Follow our [Managing adaptive content guide](/personalization/managing-adaptive-content) to immediately start delivering a personalized customer experience to your website app visitors or our [Running A/B tests guide](/personalization/defining-goals) to evaluate which variants of content A or B performs better. Source: https://docs.prepr.io/personalization/defining-goals --- # Managing segments *This guide covers everything you need to know about segments including how to manage them to unlock the full potential of Prepr’s personalization features.* ## Introduction *Segments* are groups of customers who share similar characteristics or behaviors. While *Customers* are any visitors who interact with your web app such as viewing, clicking, or liking content items. By creating segments, you can target different audiences, making it easier to deliver relevant content and experiences to your web app visitors. Before creating segments in Prepr, it's important to collect customer data to identify target audiences. Check out the [data collection docs](/data-collection/step-by-step-guide) for more details. If Prepr is not your primary source for customer profiles, you could use customer data maintained in an external CRM/CDP system with [external segments](#using-external-segments) or make use of a CRM integration like [HubSpot](//integrations/hubspot). Before diving into how to build customer segments in Prepr, first make sure to define a segment context so that editors can use the AI feature to create personalized variants. ## Defining segment context To get the best results from the AI feature that [generates personalized variants](/personalization/managing-adaptive-content#generate-ai-personalized-variants), define context for each segment used to personalize content. Make use of the example below to help you define the context for each segment. ```md copy # Target audience Electric Car Lovers ## Interests and Motivation - They are mainly interested in electric cars. - They care about sustainability, cutting-edge technology, and saving money/future-proofing. ## Consumer behavior - They research their products well before making an informed decision so they are well acquainted with terms like, zero-emission and sustainable driving. ## Characteristics They are environmentally conscious and forward-thinking. ``` To define this context, you can add it directly when [creating a segment](#building-customer-segments) by filling in the **Description for AI** field after you save your conditions. For existing segments, follow the steps below. 1. Go to the *Segments* page. 2. Click the segment you want to update from the left-side menu. 3. Click the **Settings** button to open the segment settings and fill in the **Description for AI** field with your detailed context. 4. Once done, click the **Save** button. ![Segment settings - Description for AI](https://assets-site.prepr.io/4ffnjgjbvcyf//segment-settings-description-for-ai.png) Now, you'll get more relevant results when creating AI variants in your content item. ## Building customer segments If you collect and store customer profiles in Prepr, you can build segments using this customer data. For example, you can segment customers based on personal characteristics such as where they live, events such as their page views or clicks, or UTM parameters such as the marketing campaign that routed them to your web app. Let's look at a virtual car leasing company (*Acme Lease*) as an example. While analyzing customer data, they realize that some customers are mainly interested in electric cars. So, they create a segment with conditions to match their behavior. To build this segment, follow these steps: 1. Go to **Segments → + Add segment**. 2. Set up segment conditions. For our car leasing example, the condition could be *Customers who* `did` `view` `specific items`, `Electric Lease Landing Page`, `at least once` `in the last quarter`. ![electric car lovers segment](https://assets-site.prepr.io/4rk0yko6wy1n//electric-car-lovers-segment.png) You can set up any combination of conditions in your segments for customer [*Events*](#events), customer [*Characteristics*](#characteristics), or the customer [*Source*](#source). Combine conditions by using the `AND` or `OR` logical operators. 3. If needed, you can also set up *Context* information, for example, to limit the segment to a device the customer uses when they interact with the personalized content. 4. Click the **Save** button and provide a meaningful name for the segment. The value of the *API ID* field will be generated automatically based on the segment name. You can update the value manually if needed, like in the case of an [external segment](#using-external-segments). 5. Enter some context in the **Description for AI** field to generate more relevant variants when using AI. 6. Click the **Save** button. Now that you've seen how to create a segment, let's look at the filter options in more detail to help you set up *Conditions* and the *Context* for your segments. ## Conditions When you set up conditions to build your segments, there's an extensive list of *Filter options* available. The filter options are grouped into customer *Events*, customer *Characteristics* and the customer *Source*. If you have a CRM or sales platform integration enabled, then you'll also see filter options for the applicable system such as *HubSpot* or *Dealfront*. Let's look at these options in more detail. ### Events Customer events refer to how the customer interacted with content items rendered by your web app, such as **Viewed**, **Liked**, **Clicked**, **Bookmarked**, and **Subscribed**. You can also choose a **Custom event** for any other event specific to your segmentation needs. ![Events](https://assets-site.prepr.io/57nlsq5xef2g//filter-options-events.png) These [events need to be recorded](/data-collection/recording-events) from the front end to segment the customers accurately. Once these events are recorded, Prepr automatically adds those customers to your segments according to the *Event* conditions you set up. #### Content item selection You can choose from the following list of options to define the set of content items that you want to include in the condition. ![content item selection](https://assets-site.prepr.io/5shy7rveluux//filter-options-item-selection.png) - *Any item* - The default option. Include customers who performed events on any content item. - *Specific items* - Only include customers with events on one or more specific content items. Choose the content item by its *Title* for this option. For example, *Customers who* `did` `view` `specific items` `Landing Page Electric Car` `at least once` `in the last quarter`. - *Items of a model* - Only include customers with events on content items for this model. For example, *Customers who* `did` `view` `items of a model`, `Article`, `at least once` `in the last quarter`. - *Items with specific tags* - Only include customers with events on content items with one or more tags. For example, *Customers who* `did` `view` `items with specific tags`, `Article`, `at least once` `in the last quarter`. - *Items with specific reference to item* - Only include customers with events on content items linked to specific content items. For example, *Customers who* `did` `view` `items with a reference to` `John Smith` `at least once` `in the last quarter` can group customers who viewed articles written by the person, *John Smith*. When adding a new condition for an event, the `did` action is selected by default. You can also choose the `did not` action, instead. For example, *Customers who* `did not` `view` `items of a model` `Article` `at least once`. #### Frequency options You can narrow your condition by specifying how many times an event occurred. Use one of the following options: - *At least once* - The default value. - *x number of times* - The event must occur exactly *x* times where *x* is a whole number. - *More than x times* - Only include events that happened more than *x* times where *x* is a whole number. - *Less than x times* - Only include events that happened less than *x* times where *x* is a whole number. #### Time filter You can narrow your condition to only include customers with recent activity (*Events*) by specifying when last the customer interacted with a content item. You can choose from one of the time filters below. - *In the last day* - *In the last week* - *In the last month* - *In the last quarter* (The default value) ![time filter in event conditions](https://assets-site.prepr.io/s89ln19raet//filter-options-time-filter.png) ### Source The source includes campaigns and referrals from which a customer was redirected. See a complete list below for available options and corresponding examples. ![Conditions Source](https://assets-site.prepr.io/1im99ejw5rtr//filter-options-source.png) #### Campaigns Choose one of these campaign sources to segment customers by a campaign that redirected them to your web app. - **UTM Campaign** - *Customers who* `have entered through` `UTM Campaign` `summer_car_lease_promo`. - **UTM Medium** - *Customers who* `have entered through` `UTM Medium` `email`. - **UTM Source** - *Customers who* `have entered through` `UTM Source` `newsletter`. - **UTM Content** - *Customers who* `have entered through` `UTM Content` `no_comms_button`. - **UTM Term** - *Customers who* `have entered through` `UTM Term` `car_lease_deals`. For each of these campaign options, you can choose the `not` action instead. For example: *Customers who* `have not entered through` `UTM campaign` `summer_car_lease_promo` #### Referrals You can group customers that land on your web app from another website. - **Inital referral** - *Customers who* `are visiting through a referral domain` `https://topautorev.com`. Now that you know how to set up conditions for your segments, let's look at the options you can choose for the *Context*. ### Characteristics Customer characteristics are based on data stored in the customer profile. Check out more details on [how to manage customer data](/data-collection/managing-customer-data-manually). ![Characteristics](https://assets-site.prepr.io/1ksf1per2ocd//filter-options-characteristics.png) Let's look at each of the available characteristics for segments in more detail. #### Country You can choose the *Country* option to define the customers by where they live. For the actions below, Prepr uses the *Country* in the customer profile to match the criteria. - *Did visit from* - For example, *Customers who* `did` `visit from` `Netherlands`. - *Did not visit from* - For example, *Customers who* `did not` `visit from` `United States`. #### Tags Segment customers by one of the keywords (tags) on their profile. For example, you can choose *Customers who* `are` `tagged with` `Employees` or *Customers who* `are not` `tagged with` `VIP`. Check out more technical details on [how to record these customer properties from your front end](/data-collection/recording-events#tag). #### Previous session Choose one of the time filter options to segment customers by when they last visited the web app. - *In the last # days/weeks/months* - For example, *Customers whose* `previous session was` `in the last 2 weeks`. - *Before `{date}`* - For example, *Customers whose* `previous session was` `before 7 oct 2024`. - *After `{date}`* - For example, *Customers whose* `previous session was` `after 1 aug 2024`. - *Between `{date}` and `{date}`* - For example, *Customers whose* `previous session was` `between 25 jul 2024 and 1 aug 2024`. #### First seen Choose one of the time filter options to segment customers by when they first visited the web app. - *In the last # days/weeks/months* - For example, *Customers who* `were first active` `in the last 2 weeks`. - *Before `{date}`* - For example, *Customers who* `were first active` `before 7 oct 2024`. - *After `{date}`* - For example, *Customers who* ` were first active` `after 1 aug 2024`. - *Between `{date}` and `{date}`* - For example, *Customers who* `were first active` `between 25 jul 2024 and 1 aug 2024`. #### Visits Choose one of the options to segment customers by how many times they visited the web app. - *# times* - For example, *Customers who* `visited` `5 times`. - *More than # times* - For example, *Customers who* `visited` `more than 10 times`. - *Less than # times* - For example, *Customers who* `visited` `less than 3 times`. #### Signed up Segment customers by who've signed up or not signed up. Check out [the data collection docs](/data-collection/recording-events#signup) for more details on recording this customer event in Prepr. #### Email address You can include customers that have or don't have an email address. ### HubSpot With this condition you can group customers who belong to a segment defined in HubSpot, for example, for a HubSpot list based on contacts who are marked as leads. ![HubSpot segment](https://assets-site.prepr.io/3tioj9i5pi4d//filter-options-hubspot.png) Check out the [HubSpot doc](/integrations/hubspot) on how to activate the integration. ### Dealfront With this condition you can group B2B customers who belong to a segment defined in Dealfront, for example, for visitors from the *Retail* or *Manufacturing* industries or to specifically target small to medium companies. ![Dealfront segment](https://assets-site.prepr.io/ymnur8lhfb7//filter-options-dealfront.png) Check out the [Dealfront doc](/integrations/dealfront) on how to activate the integration. ## Context In addition to the conditions, you can also define a current context for the segment. The *Context* of a segment includes current info about the customer when they interact with personalized content. You can select the options below to define a *Context*. ### Current country You can define the segment in the context of the country that the customers are currently visiting the web app from. For example, *Customers who are* `currently visiting from` `United States`. ### Current device You can define the segment in the context of the device that the customers are currently using or not currently using. For example, *Customers who are* `currently using` `a mobile device` or *Customers who are* `not currently using` `a mobile device`. ### HTTP header You can define the segment in the context of an HTTP header value, such as the web app version the customers are currently using. For example, *Customers who are* `currently requesting with HTTP header` `APP-Version` `is greater than 1`. **Semantic versioning (SemVer)** You can add conditions with semantic versions to compare more accurate version numbers like `1.0.3`. ![http header context with semantic versioning](https://assets-site.prepr.io/2x3whzthejbi//segments-context-condition-semversion.png) ### Current Day You can define a segment by the current day that a customer visits. For example, *Customers who are* `visiting on` `Saturday` `or` `Sunday` to target weekend visitors. ### Current Time You can define a segment by the current time that a customer visits. For example, *Customers who are* `visiting` `between 06:00 and 12:00` to target morning visitors. Now that you know how to build segments, you're ready to manage your adaptive content. Check out the [Managing adaptive content guide](/personalization/managing-adaptive-content) for more details. ## Organize segments into folders When you have dozens of segments, folders make it easy to find related segments. For example, when you have multiple segments for marketers who want to track fleet customers. ![Add segment to new folder](https://downloads-site.prepr.io/7egmne226mra-organize-segments.gif) Hover over your segments and click the icon. In the *Add folder* dialog, enter a name for the new folder. Once the folder is created, you can drag and drop the segments you want to include in the new folder. To remove segments from the folder simply drag and drop the segments outside the folder. Click the icon next to the folder name to either rename the folder by clicking the **Edit** option or **Delete** the folder. The folder structure will be removed and the included models will return to the alphabetical list of models\*\*.\*\* ## Using external segments If you manage your customer segments in an external system such as a CRM/CDP system and want to use them in Prepr, you can create segments that reference those external segments as follows: 1. Go to **Segments → + Create segment**. You'll notice that a default condition is partially filled. 2. Click the x icon to delete the condition and enter a name for the segment. 3. Click the **Save** button. 4. Provide a meaningful name for the segment. ![External segment](https://assets-site.prepr.io/6wnwjtxy5ex9//external-segment-example.png) 5. Copy and paste the segment unique identifier from your CRM/CDP system to replace the automatically generated *API ID* value in Prepr. 6) Click the **Save** button. This setup will work as a reference to the segment created in the external system, so you don't need to specify any conditions for this segment in Prepr. ## What’s next? Follow our [Managing adaptive content guide](/personalization/managing-adaptive-content) to immediately start delivering a personalized customer experience to your website app visitors. Source: https://docs.prepr.io/personalization/managing-segments --- # Managing adaptive content *This guide shows you how to personalize your website to improve engagement and user experience.* ## Introduction Prepr lets you create personalized experiences with *Adaptive content*. With *Adaptive content*, you can make different versions of content for various visitor segments. You can then show the right content to each visitor based on their segment giving them a personalized experience. ## Use case Let's look at a typical use case. You want to increase the number of visitors who request a quote through your car leasing website. To achieve this goal, you take the following actions: 1. You find that the *Home* page is one of the main entry points in the customer journey that starts from clicking the **Find a car** CTA button and resulting in a quote request. ![Home page customer journey](https://downloads-site.prepr.io/3volgjiwvqj6-home-page-customer-journey.gif) 2. So, you come up with a plan to improve the content in the hero section of the home page. - You decide to group customers by those who want to lease electric cars. - You prepare personalized content for this targeted audience to drive more visitors toward the ultimate goal of requesting a quote. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) 3. To determine how well this personalized variant of the Hero section performs, you add it as adaptive content with the following goals: - Micro-conversion goal: You want to measure how many customers click the **Find your car** button on the home page because it's the start of the customer journey to reach the end goal. - Macro-conversion goal: You want to measure how many customers request a quote within a day of visiting the home page. **General website visitors** When customers navigate to the Acme Lease home page, they see a generic page like in the image below. ![Acme lease home page](https://assets-site.prepr.io/p6rja5r1cj8//dynamic-website-with-prepr-content.png) **Visitors interested in leasing an electric car** When a potential customer searches for an electric lease car and clicks an Acme Lease ad, they are directed to the electric lease landing page on the Acme Lease website. If they visit the home page again later, they'll see content focused on electric lease cars instead of the generic home page above. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) For this use case, the front-end application tracks each visitor's behavior based on their interests. When a visitor views the *Electric Lease Landing Page*, Prepr places them in the *Electric Car Lovers* segment. This is just one way to set up adaptive content. You could also set up adaptive content based on other characteristics such as location or device. You could even add adaptive content based on criteria outside of the web app, for example, when a user visits your web app from a social media link. Check out the [Managing segments doc](/personalization/managing-segments) for more details. ## Prerequisites To add adaptive content to your website like in the above example, you need to have the following set up in Prepr: - [A Prepr CMS account](https://signup.prepr.io/?plan=free) ## Personalize your website To personalize your website, you need to complete the following steps: 1. Set up segments based on specific visitor interaction on the content. These segments are the groups of visitors for whom you want to deliver a personalized experience. 2. Define conversion goals to get deeper insights into how well this experiment works for customer experience. 3. Add an adaptive content element. For each segment, create content specifically aimed at those groups of visitors. 4. Manage the adaptive content by updating the adaptive content settings, if necessary. 5. Evaluate the adaptive content variants. Prepr collects metrics on the performance of the pages with adaptive content. You can use this data to adjust the content in these pages or the segments' criteria. Congratulations, you have successfully personalized your website. ## Other use cases This guide explains just one use case for personalization. Below we list a few more common options. ### Segments from external CRM/CDP systems It's possible to personalize Prepr content based on segments maintained in other CDP/CRM systems. In this case, you need to reference these external segments from within Prepr using the segment unique identifier from that system. Your personalization flow will look like this: 1. [Create a new segment in Prepr](/personalization/managing-segments#use-external-segments-from-crmcdp-systems) and set the *ID* value to the segment unique identifier copied from your CRM/CDP system. 2. [Add an adaptive content element](#add-an-adaptive-content-element). 3. The developer then [retrieves adaptive content using the API](/personalization#retrieve-adaptive-content-using-the-api) with one difference — they pass the `Prepr-Segments` header instead of the `Prepr-Customer-Id`. ### Call-to-actions Personalizing call-to-actions can significantly increase conversion rates. Offer each segment the call-to-action that fits best. For example, show a relevant whitepaper to first-time visitors and offer a demo to returning visitors. ### Categories Do you have content or products in different categories? Capture which categories your visitors view and display them on the homepage on their next visit. ## Want to learn more? Check out the following guides: - [Collecting event data](/data-collection) - [Defining goals](/personalization/defining-goals) - [Managing segments](/personalization/managing-segments) - [Recommendations](/ab-testing/running-ab-tests) ## Schedule a free consultation Do you want to get started with personalization 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/personalization/managing-adaptive-content --- # Setting up A/B testing *Estimated duration: 15-30 minutes* *This guide demonstrates how to set up A/B testing and the related metrics in your web application using the Prepr GraphQL API.* ## Introduction A/B testing is a simple and efficient way to compare two versions of something to figure out which performs better. In Prepr, marketers can create variants of any section or heading text field in a content item. In your front-end app, you can then render the variants in your website to show each to separate groups of visitors. ## Use cases Let's look at a couple of use cases. ### Test hero section on landing page The marketing team wants to increase conversions and they've prepared two sets of content for the same section but are unsure which one will drive more customers toward these goals. In this case, they run an A/B test. The image below is an A/B test example in a car leasing website. It shows the A and B variants of the hero section on the *Electric Lease* landing page. ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) Once implemented, Prepr starts measuring the conversion rate for each variant and determines which is more effective. ### Test blog post headlines The marketing team wants to increase conversions and they've prepared variants of blog post headlines, but are unsure which one will drive more customers toward these goals. In this case, they create an A/B test for each of the recommended blog posts. ![A/B test on headlines example](https://assets-site.prepr.io/1bucoa9008l0//ab-test-blog-post-headlines-example.png) Once implemented, Prepr measures the conversion rate for each variant and determines which headline is more effective. ## Prerequisites To set up your front end for A/B testing according to the guide below, you need to have the following set up in Prepr: - [A Prepr CMS account](https://signup.prepr.io/?plan=free) ![A/B test in Electric lease content item](https://assets-site.prepr.io/6l4bf1thuzjc//ab-test-example-electric-landing-page.png) ## Set up your front end for A/B testing Before setting up your front end for A/B testing, make sure to [enable Prepr tracking](/data-collection/setting-up-the-tracking-code) and [add the content item meta tag](/data-collection/recording-events#tracking-content-items) to track visitors when they view pages. When A/B testing an individual text field for a multi-locale web app, make sure to set up the [locale meta tag](/data-collection/recording-events#tracking-for-text-field-ab-testing). To prepare your frontend application for A/B testing, follow these steps: 1. Create a customer ID to track and link each visitor to a variant. 2. Retrieve the A/B test content for the matching variant using the API. 3. Record custom events, if needed, for segment or goal definitions. 4. Track impressions and conversions for a stack element or for a text field. Congratulations, you have successfully set up A/B testing in your front end. Check out the next section if you are implementing a static website. ## Implementing A/B testing for static (SSG) websites Unlike dynamic sites, static sites serve pre-built content to a web browser without calls to a database. To perform A/B testing for static site rendering, you need to set up variants ahead of time (particularly before you build the web app) and then split traffic between different routes using the edge middleware ([see an example tool](https://vercel.com/docs/functions/edge-middleware/quickstart)). Let’s see it in detail. The A/B testing for static site rendering looks like this: 1. On pages where an A/B test needs to be triggered, you call the API to [pre-fetch variants](/graphql-api/personalization-recommedations-ab-testing#pre-fetching-the-variant). Your request must include the following fields: - *\_context* - system field that contains additional details about variants such as the following fields: - *kind* – returns a value of *PERSONALIZATION* or *AB\_TEST*. - *variant* - returns a value of *A* or *B* if *kind* has a value of *AB\_TEST* Here’s an example code snippet. Update the id string of the query with your *Content item ID* (find the ID in the right-hand column on the *Page* content item in Prepr). 2. When a user visits your web app, you make a one-time request to know if this user is assigned to *Bucket A* or *Bucket B*. Your request must include the following headers: - *Prepr-Customer-ID* with a session ID of a visitor - *Prepr-Bucket-Customer = true* The bucketing runs at the edge location of the CDN and takes no longer than 7 ms. A response to your API request contains a header – either *X-Prepr-Customer-Bucket A* or *X-Prepr-Customer-Bucket B*. See an example request below: ```curl copy curl --location --globoff 'https://graphql.prepr.io/' \ --header 'Prepr-Customer-ID: 409ad1af-d644-4d3f-8cb9-691c0318a980' \ --header 'Prepr-Bucket-Customer: true' ``` 3. With this information, the front-end middleware can redirect a visitor to a respective variant of your A/B test. For all the requests from the same visitor, the same variant will be shown. ## Want to learn more? Check out the following guides: - [Collecting event data](/data-collection) * [Defining goals](/personalization/defining-goals) - [Connecting your front-end application](/connecting-a-front-end-framework) - [Setting up personalization](/personalization/setting-up-personalization) ## Schedule a free consultation Do you want to get started with A/B testing 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/ab-testing/setting-up-ab-testing --- # Running A/B tests *This guide shows you how to easily run A/B tests in Prepr CMS.* ## Introduction Let's look at a typical use case for an A/B test. You want to increase the number of visitors who request a quote through your car leasing website. To achieve this goal, you take the following actions: 1. You find that the *Electric Lease* landing page is one of the main entry points in the customer journey that starts from clicking the **Find a car** button and resulting in a quote request. ![Electric lease landing page customer journey example](https://downloads-site.prepr.io/2uz76b880tm5-electric-lease-customer-journey.gif) 2. So, you come up with a plan to improve the content in the hero section of this landing page. You prepare two variants of the hero section (variants A and B) but are unsure which one will most effectively drive visitors toward requesting a quote. ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) 3. To determine which variant performs best, you run an A/B test with the following goals: - Micro-conversion goal: You want to measure how many customers click the **Find your car** button on the *Electric Lease Landing Page* because it's the start of the customer journey to reach the end goal. - Macro-conversion goal: You want to measure how many customers request a quote within a day of visiting the home page. ## Prerequisites To run A/B testing on your website like in the above example, you need to have the following set up in Prepr: - [A Prepr CMS account](https://signup.prepr.io/?plan=free) ## Create an A/B test in Prepr Congratulations, you have successfully implemented an A/B test and used it to improve the customer experience on your web app. ## Want to learn more? Check out the following guides: - [Collect event data](/data-collection) - [Define conversion goals](/personalization/defining-goals) - [Manage segments](/personalization/managing-segments) - [Personalize website](/personalization/setting-up-personalization) ## Schedule a free consultation Do you want to get started with A/B testing 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/ab-testing/running-ab-tests --- # ActiveCampaign *In this guide, you’ll learn how to activate the ActiveCampaign integration in Prepr CMS. This integration allows marketers to add signup forms to feed contacts directly into their marketing automations.* ## Introduction ActiveCampaign is a cloud-based marketing automation platform that helps businesses automate customer experiences. If your tech stack includes ActiveCampaign as your primary marketing platform, you can add signup forms directly in Prepr. Source: https://docs.prepr.io/integrations/activecampaign --- # Algolia *From this guide, you’ll learn how to index Prepr content with the Algolia search engine for an optimized and performant search experience in your web app.* ## Introduction If you value a good customer experience, you might think about how web visitors search across your app. Can they easily find what they are looking for? Are they receiving the most up-to-date content? Web users have a short attention span, so it's crucial to provide them with relevant search results to maintain their loyalty. Prepr supports integration with [Algolia](https://www.algolia.com/), an AI-powered search service with a high-performance API. It enables your Prepr content items to be indexed using the Algolia algorithm, maximizing the search speed and content discovery in your web app. ## First things first Note the following important factors before setting up the Algolia integration. These give you a good understanding of the impact on record size and related cost, how records are split and the search performance. ### Record size limits There are [record size limits](https://support.algolia.com/hc/en-us/articles/4406981897617-Is-there-a-size-limit-for-my-index-records) based on your Algolia plan. Make sure you understand the impact of exceeding these limits before setting up the Algolia integration. ### Improving search results and performance You can easily improve search results and performance by configuring Algolia attributes: - [Searchable attributes](https://www.algolia.com/doc/guides/managing-results/must-do/searchable-attributes/) - [Attributes for the custom ranking](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#custom) - [Attributes for deduplication](https://www.algolia.com/doc/guides/managing-results/refine-results/grouping/) ## Setting up the Algolia integration Follow the steps below to set up your Algolia integration to search Prepr content in your web app. ## Syncing existing content and schema updates The setup steps above allow you to index all new content created after enabling the Algolia integration. If you need to index any content you already have, or after a schema update, you need to run the sync action manually. To sync content items to Algolia manually, you must call the given Prepr endpoint and specify a model ID, which you can find under **Schema → Model → → Copy Model ID**. Content items will be synced in batches, the overall time depends on the number of content items you have. The following API request will sync content items to Algolia: ```http copy GET: https://api.eu1.prepr.io/publications/algolia/sync ``` ```json copy { "model": { "id": "YOUR_MODEL_ID" } } ``` Source: https://docs.prepr.io/integrations/algolia --- # BigCommerce *This integration allows content editors to select BigCommerce products in Prepr content items.* ## Introduction You can connect Prepr to [BigCommerce](https://www.bigcommerce.com/), a platform including online store creation, search engine optimization, hosting, and marketing and security from small to Enterprise sized businesses. This integration allows you to view and search the BigCommerce catalog directly in Prepr and include products in your web app content. ## Activating BigCommerce integration That’s it. Now your web page includes catalog data from BigCommerce. Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/integrations/bigcommerce --- # Bynder *This integration allows content editors to select media from a Bynder account in content items.* ## Introduction Bynder is a digital asset management platform. If your tech stack includes Bynder as your primary asset management system, you can use the Bynder-stored assets directly in Prepr. This means it's possible for content editors to use those assets in their content items. Source: https://docs.prepr.io/integrations/bynder --- # Cloudinary *This integration allows content editors to select media from a Cloudinary account in content items.* ## Introduction Cloudinary provides cloud-based image and video management services. If your tech stack includes Cloudinary as your primary digital asset management system, you can use the Cloudinary-stored assets directly in Prepr. This means it's possible for content editors to use those assets in their content items. Source: https://docs.prepr.io/integrations/cloudinary --- # Commerce Layer *This article describes how to add the Commerce Layer catalog data to your web application using Prepr.* ## Introduction Prepr supports a native integration with [Commerce Layer](https://commercelayer.io/), an API-first commerce platform. This integration allows you to view and search the Commerce Layer catalog directly in Prepr and include products in your web app content. You can activate the Commerce Layer integration by following the steps below. ## Activating Commerce Layer integration That’s it. Now your web page includes content inserts from Commerce Layer. In addition, Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/integrations/commerce-layer --- # Commercetools *This article describes how to add the Commercetools catalog data to your web application using Prepr.* ## Introduction Prepr supports native integration with [Commercetools](https://commercetools.com/), a cloud-based headless commerce solution. This integration allows you to view and search the Commercetools catalog directly in Prepr and include products in your web app content. You can activate the Commercetools integration by following the steps below. ## Activating Commercetools integration That’s it. Now your web page includes content inserts from Commercetools. Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/integrations/commercetools --- # Customer.io *This integration allows you to sync customer segments from this messaging platform.* ## Introduction Customer.io is a messaging platform used by marketers to created automated message campaigns. If Customer.io is your primary customer data management system, then you can integrate your defined customer segments to Prepr. Source: https://docs.prepr.io/integrations/customerio --- # Dealfront (Leadfeeder) *In this guide, you’ll learn how to activate the Dealfront integration in Prepr CMS. This integration provides you with the website visitor's industry and company size you can use to create segments for personalization.* ## Introduction Dealfront is a comprehensive sales intelligence platform. It offers Leadfeeder’s website visitor tracking to identify which companies visit your website. ## Activating Dealfront integration to identify visitors That’s it. The Dealfront integration is activated and you can create adaptive content for your B2B website visitors. Source: https://docs.prepr.io/integrations/dealfront --- # Form.io *In this guide, you’ll learn how to activate the Form.io integration in Prepr CMS. This integration allows marketers to embed interactive forms and collect responses directly in your content.* ## Introduction Form.io is a powerful form builder that allows you to create complex forms, integrate APIs, and manage workflows. If your tech stack includes Form.io to maintain your forms, you can add Form.io forms directly in Prepr. Source: https://docs.prepr.io/integrations/formio --- # Formstack *In this guide, you’ll learn how to activate the Formstack integration in Prepr CMS. This integration allows marketers to embed interactive forms and collect responses directly in your content.* ## Introduction Formstack is an all-in-one platform that helps organizations to create digital forms, generate documents, and collect digital signatures. If your tech stack includes Formstack to maintain your forms, you can add Formstack forms directly in Prepr. Source: https://docs.prepr.io/integrations/formstack --- # Frontify *In this guide, you’ll learn how to activate the Frontify integration in Prepr CMS. This integration allows content editors to access Frontify brand assets to make sure that their content is brand-compliant.* ## Introduction Frontify is a brand management platform. If your tech stack includes Frontify as the primary system for your branded assets, you can use the Frontify-stored branded assets directly in Prepr content. This means it's possible for content editors to use those assets in their content items. ## Use Frontify assets in Prepr You can enable the Frontify integration to use Frontify assets in Prepr CMS by following the steps below. That’s it. The Frontify integration is activated and your web page includes content with embedded images from Frontify. Source: https://docs.prepr.io/integrations/frontify --- # FTP Server *This integration allows you to connect to an FTP server to import video and audio assets automatically.* ## Introduction An FTP server makes files available for download via a file transfer protocol. By activating an integration to an FTP server in Prepr, assets will automatically be imported into the *Media Library* from the FTP server that you define. These assets are then available for your content editors to include them in any content items. ## Activate FTP server Simply activate the FTP server integration with the following steps: 1. Click the icon and choose the **Integrations** option. Go to the **FTP Server** card and click the **Activate** button. 2. Fill in the connection details of your FTP server and click the **Save** button. ![Activate FTP server](https://downloads-site.prepr.io/7kyu2zkuq39w-activate-ftp-server.png) To make changes to the connection details, go back to the **FTP Server** block and click the **Manage** button to make your changes. If you have any questions, please [contact our Support team](https://prepr.io/support). Source: https://docs.prepr.io/integrations/ftpserver --- # Google Workspace *Integrate this cloud-based suite of business collaboration tools to streamline your authentication permissions in your organization.* ## Introduction Prepr offers several ways to log in: Using a passkey, single sign-on or by submitting an email address with a password. Single sign-on (SSO) is a way to authenticate and log in to an application with just one set of credentials, rather than having to set up multiple usernames and passwords across different platforms. It's a more secure process and prevents potentially losing or forgetting log-in credentials since it's stored through another service. You can integrate with Google Workspace if you want to let users sign-in through your company Google Workspace. Check out this [step-by-step guide](/project-setup/setting-up-sso#google-workspace) on how to set up SSO with Google Workspace. Source: https://docs.prepr.io/integrations/google-workspace --- # HubSpot *In this guide, you’ll learn how to activate the HubSpot integration in Prepr CMS. This integration allows you to include HubSpot lists in your Prepr segments allowing you to render adaptive content to known HubSpot contacts. By activating this integration, you also allow editors to include HubSpot forms in their content items.* ## Introduction HubSpot is a CRM used to generate leads, close deals and improve customer experiences. If HubSpot is your primary system to manage customers, visitor identification and/or forms, then you can integrate HubSpot lists and HubSpot forms to Prepr. ## Activating HubSpot integration That’s it. The HubSpot integration is activated and you can create adaptive content for your HubSpot contacts and include HubSpot forms in your content items. Source: https://docs.prepr.io/integrations/hubspot --- # JotForm *In this guide, you’ll learn how to activate the JotForm integration in Prepr CMS. This integration allows marketers to embed interactive forms and collect responses directly in your content.* ## Introduction JotForm is an online form builder that allows users to create and manage custom online forms, apps, and e-signatures . If your tech stack includes JotForm to maintain your forms, you can add JotForm forms directly in Prepr. Source: https://docs.prepr.io/integrations/jotform --- # Mailchimp *In this guide, you’ll learn how to activate the Mailchimp integration in Prepr CMS. This integration allows marketers to embed interactive forms and collect responses directly in your content.* ## Introduction Mailchimp is a comprehensive marketing platform that is not only an email marketing service but includes website building, social media marketing, and customer relationship management (CRM) tools. If your tech stack includes Mailchimp to maintain your forms, you can embed Mailchimp signup forms directly in Prepr. Source: https://docs.prepr.io/integrations/mailchimp --- # Microsoft Entra ID (Azure) *Integrate this cloud-based identity management solution to streamline your authentication permissions in your organization.* ## Introduction Prepr offers several ways to log in: Using a passkey, single sign-on or by submitting an email address with a password. Single sign-on (SSO) is a way to authenticate and log in to an application with just one set of credentials, rather than having to set up multiple usernames and passwords across different platforms. It's a more secure process and prevents potentially losing or forgetting log-in credentials since it's stored through another service. You can integrate with Microsoft Entra ID (Azure) if you want to let users sign-in through your company Microsoft Entra ID account. {/* An additional agreement for Prepr is required to enable the Microsoft Entra ID (Azure) app. */} Check out this [step-by-step guide](/project-setup/setting-up-sso#microsoft-entra-id) on how to set up SSO with Microsoft Entra ID. Source: https://docs.prepr.io/integrations/azure --- # OpenID Connect *Integrate this secure authentication protocol built on top of OAuth 2.0 to streamline your authentication permissions in your organization.* ## Introduction Prepr offers several ways to log in: Using a passkey, single sign-on or by submitting an email address with a password. Single sign-on (SSO) is a way to authenticate and log in to an application with just one set of credentials, rather than having to set up multiple usernames and passwords across different platforms. It's a more secure process and prevents potentially losing or forgetting log-in credentials since it's stored through another service. You can integrate with an identity provider using the OpenID Connect open standard if you want to let users sign-in through your company IdP. Check out this [step-by-step guide](/project-setup/setting-up-sso#openid-connect-oidc) on how to set up SSO with OpenID Connect. Source: https://docs.prepr.io/integrations/openid --- # Pipedrive *In this guide, you’ll learn how to activate the Pipedrive integration in Prepr CMS. This integration allows content editors to embed Pipedrive forms in their content items.* ## Introduction Pipedrive is a sales CRM and pipeline management software. ## Activating Pipedrive integration That’s it. The Pipedrive integration is activated and you can embed Pipedrive forms in content items. Source: https://docs.prepr.io/integrations/pipedrive --- # Prepr Image Processing *This integration allows you to add Exif data to your assets automatically.* ## Introduction Exif (Exchangeable image file format) is a standard that specifies formats for media files. When you activate *Prepr Image Processing*, you can add an Exif title, description and author to your assets. ## Activate Exif Simply activate the Exif integration with the following steps: 1. Click the icon and choose the **Integrations** option to view all integrations. Go to the **Exif** card and click the **Activate** button. 2. Enable a toggle to fetch the *Artist* (jpg.exif.IFD0.Artist or xmp.pdf.Author), the *Description* (jpg.exif.IFD0.ImageDescription, xmp.dc.description.0) or the *Name* (iptc.comments.IPTCApplication.ObjectName.0) data from Exif and click the **Save** button. ![Activate exif](https://downloads-site.prepr.io/40cfeoe7e2xd-activate-exif.gif) To make changes to the options, go back to the **Exif** block and click the **Manage** button to make your changes. If you have any questions, please [contact our Support team](https://prepr.io/support). Source: https://docs.prepr.io/integrations/exif --- # Salesforce *This integration allows you to sync customer segments from a Salesforce account to Prepr.* ## Introduction Salesforce includes CRM software that manages customer data, sales operations and marketing campaigns. If you use Salesforce as your primary customer data management platform, then you can integrate customer segments to Prepr. Source: https://docs.prepr.io/integrations/salesforce --- # SAML 2.0 *Integrate any identity provider (IdP) with this open standard to provide a cross-domain single sign-on (SSO) solution to streamline your authentication permissions in your organization.* ## Introduction Prepr offers several ways to log in: Using a passkey, single sign-on or by submitting an email address with a password. Single sign-on (SSO) is a way to authenticate and log in to an application with just one set of credentials, rather than having to set up multiple usernames and passwords across different platforms. It's a more secure process and prevents potentially losing or forgetting log-in credentials since it's stored through another service. You can integrate with an identity provider using the SAML 2.0 open standard if you want to let users sign-in though your company identity provider. Check out this [step-by-step guide](/project-setup/setting-up-sso#saml-20) on how to set up SSO with a SAML 2.0 identity provider. Source: https://docs.prepr.io/integrations/saml --- # Shopify *This integration allows content editors to select Shopify products in Prepr content items.* ## Introduction You can connect Prepr to [Shopify](https://www.shopify.com/), a cloud-based commerce platform for creating and managing online stores. This integration allows you to view and search the Shopify catalog from within Prepr and include products, product variants and collections in your web app content. ## Activating Shopify integration That’s it. Now your web page includes catalog data from Shopify. Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/integrations/shopify --- # Snitcher *In this guide, you’ll learn how to activate the Snitcher integration in Prepr CMS. This integration provides you with the website visitor's company profile data you can use to create segments for personalization.* ## Introduction Snitcher is a B2B website visitor identification platform that identifies anonymous companies visiting a website by name and tracks their behavior. You can integrate with Snitcher to create segments in Prepr based on the visitor's company profile data. ## Activating Snitcher integration to identify visitors That’s it. The Snitcher integration is activated and you can create adaptive content for your B2B website visitors. Source: https://docs.prepr.io/integrations/snitcher --- # Twilio Segment *This integration allows you to sync customer segments from a Twilio Segment account to Prepr.* ## Introduction Segment is a customer data platform that captures and consolidates customer data into user profiles and audiences. If Segment is your primary customer data management system, then you can integrate your defined customer segments to Prepr. Source: https://docs.prepr.io/integrations/segment --- # Typeform *Follow this guide to learn how to embed the Typeform templates in your web application.* ## Introduction The Prepr integration with [Typeform](https://www.typeform.com/), an online form-building platform, lets you reference your form templates right inside Prepr. As a result, editors can easily search, preview, and add interactive web forms in content items. You can make Typeform templates avaiable in content items by following the steps below. ## Activate Typeform integration for form content That’s it. With this result, you have all the data to include the form from Typeform in your web application. In addition, Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/integrations/typeform --- # Typesense *This integration allows you to use the Typesense search engine for an optimized search experience on Prepr content in your web app.* ## Introduction Prepr supports integration with Typesense, an open source, typo tolerant search engine. It enables your Prepr content items to be indexed using the Typesense algorithm, maximizing the search speed and content discovery in your web app. ## Integrating Typesense with Prepr content Source: https://docs.prepr.io/integrations/typesense --- # Vercel *In this guide, you’ll learn how to set up the Vercel integration to deploy your website directly in Prepr CMS.* ## Introduction Vercel is a cloud platform that automates front-end deployments for speed and efficiency. When editors publish content changes in Prepr CMS, these changes appear in the live website. However, [for statically deployed sites](/development/best-practices/csr-ssr-ssg#static-site-generation-ssg), content changes are only visible after a rebuild and deployment. The Vercel integration mitigates this by allowing users to deploy to Vercel directly from Prepr, ensuring the website updates with the latest published content as needed. ## Enabling Vercel deployment in Prepr That’s it. The Vercel integration is activated and any user can now build and deploy directly in Prepr. Source: https://docs.prepr.io/integrations/vercel --- # Zapier *In this guide, you’ll learn how to set up a Zapier integration to send data from any listed external system to Prepr CMS.* ## Introduction Zapier is an automation tool that connects apps and services, allowing users to create workflows (called *Zaps*) that trigger actions between them without coding. ![zapier](https://assets-site.prepr.io/jq5gxlf9bvq//zapier-prepr-integration.png) We've set up two types of workflows to pair any app with Prepr. - **Tag a Customer Profile** - Creates a tag on the matching Prepr customer profile with a value from the external system. - **Track event** - Records an event for a matching customer in Prepr based on an action in the external system. Before creating a *Zap*, you need to get the access token for the Prepr environment that Zapier needs to connect to. ## Getting the Prepr access token Go to your Prepr environment to get the access token to use in the Zapier workflow as follows: 1. Go to **Settings → Access tokens**. 2. If you don't have an [access token](/mutation-api/authorization) for REST API requests, click the **Add access token** button. 3. In your REST API access token, click the **Edit scopes** button to add the `capture_publish` REST API scope and click the **Save** button. ![mutation access token](https://assets-site.prepr.io/1qi7u08ylfuu//mutation-access-token.png) 4. Click the icon to copy the **Access token** value. Now that you have the access token, you can create a *Zap*. ## Creating a *Zap* To create a *Zap*, go to the [Prepr's Zapier integration page](https://zapier.com/apps/prepr/integrations). ### Tag a Customer Profile This action is useful when you need to send some customer data from another system to Prepr for segmentation. For example, you can send the `industry` of a known customer in Prepr when they request a demo through a HubSpot form. Create a *Zap* to tag a customer profile in Prepr with the following steps: 1. In the [Prepr's Zapier integration page](https://zapier.com/apps/prepr/integrations), choose a pairing app, for example, **HubSpot**. 2. Choose a trigger, for example, **New Form Submission**, choose **Tag a Customer Profile** for the action and click the **Connect these apps** button. Zapier creates the basic workflow (*Zap*) and you can customize it according to your needs. 3. Log in to your account for the app you paired and click the **Continue** button. 4. Depending on the trigger you chose, you'll need to choose some additional info, for example, a Demo request form. 5. Click the **Test trigger** button and choose any record for the test. 6. Click the **Sign in** button and paste the access token you copied from your Prepr environment. 7. In the **Tags** field, click the icon and choose the field you want to add. Enter the email address of the matching customer in Prepr. Click the **Test step** button. You'll see a message about the tag being sent to Prepr. ![HubSpot Zap](https://assets-site.prepr.io/1f45wvd0mx1i//hubspot-zap-successful-test.png) 8. In your Prepr environment, go to the **Segments** tab and open the customer that you matched in the test. You'll see a new tag for that customer matching the field value in the paired app. 9. In Zapier, click the **Publish button** to activate the integration. The integration to Prepr is now activated and Zapier automatically sends customer data from the paired app to create a tag in Prepr for any matching customer. ### Track Event This action is useful when you need to trigger Prepr to create an event for segmentation. For example, when you want to create the [*Subscribe* event](/data-collection/recording-events#subscribe) whenever a someone new subscribes to your Mailchimp newsletter. 1. In [Prepr's Zapier integration page](https://zapier.com/apps/prepr/integrations), choose a paired app, for example, **Mailchimp**. 2. Choose a trigger, for example, **New Subscriber**. Choose **Track Event** for the action and click the **Connect these apps** button. Zapier creates the basic workflow (*Zap*) and you can customize it according to your needs. 3. Sign in to your account for the paired app and click the **Continue** button. 4. Depending on the paired app, you need to choose additional info, for example, the Mailchimp **Audience**, and click the **Continue** button. 5. Click the **Test trigger** button and choose any record for the test. 6. Click the **Sign in** button and paste the access token you copied from your Prepr environment. 7. Enter a value for the [Event Name](/data-collection/recording-events), for example, *Subscribe*, and enter the email address or external ID to match the customer in Prepr. Click the **Test step** button. You'll see a message about an event being sent to Prepr. ![Mailchimp test](https://assets-site.prepr.io/4ns6cqc7yfd//mailchimp-zap-successful-test.png) 8. In your Prepr environment, go to the **Segments** tab and open the customer that you matched in the test. You'll see a new event recorded for that customer. 9. In Zapier, click the **Publish button** to activate the integration. The integration to Prepr is activated and Zapier triggers Prepr to create an event for every matching customer in the paired app for the chosen trigger. Source: https://docs.prepr.io/integrations/zapier --- # Laravel GraphQL Provider for Prepr CMS This Laravel package is a provider for the Prepr GraphQL API. ## Basics - The SDK on [GitHub](https://github.com/preprio/laravel-graphql-sdk) - Compatible with Laravel `v11x`. ## How to install Install Package ``` composer require preprio/laravel-graphql-sdk ``` Added config in you're .env file and config/services.php ```php filename="config/services.php" copy 'prepr' => [ 'endpoint' => env('PREPR_ENDPOINT') ] ``` ```bash filename=".env" copy PREPR_ENDPOINT={YOUR_API_ENDPOINT} ``` ## Query the API Option with query file (create file in app/Queries with .graphql extension): ```js copy $response = Http::prepr([ 'query' => 'name-of-the-file', 'variables' => [ 'id' => 123, ] ]); ``` Option without a query file: ```js copy $response = Http::prepr([ 'raw-query' => 'query here', 'variables' => [ 'id' => 123, ] ]); ``` Option with headers ```js copy $response = Http::prepr([ 'query' => 'name-of-the-file', 'variables' => [ 'id' => 123 ], 'headers' => [ 'Prepr-Customer-Id' => request()->get('customer_id',request()->session()->getId()) ] ]); ``` Source: https://docs.prepr.io/laravel/laravel-graphql-provider --- # Laravel Rest Provider for Prepr CMS This Laravel package is a provider for the Prepr REST API. ## Basics - The SDK on [GitHub](https://github.com/preprio/laravel-rest-sdk) - Compatible with Laravel `v5x`, `v6x`, `v7x`, `v8x`, `v9x`, `v10x`, `v11x`. - Requires `GuzzleHttp 7.3.X`, and for version 3.0 and above PHP 8.x is required. ## Installation You can install the Provider as a composer package. For Laravel v10x and Laravel v11x ```bash copy composer require preprio/laravel-rest-sdk:"^4.0" ``` For Laravel v9x ```bash copy composer require preprio/laravel-rest-sdk:"^2.0" ``` For Laravel v8x ```bash copy composer require preprio/laravel-rest-sdk:"^1.3" ``` Other versions ```bash copy composer require preprio/laravel-rest-sdk:"1.1" ``` ### Publish config Publish `prepr.php` config ```php filename="prep.php" copy php artisan vendor:publish --provider="Preprio\PreprServiceProvider" ``` ## Set up your .env file configuration You can set the default configuration in your .env file of you Laravel project. ```bash filename=".env" copy PREPR_URL=https://cdn.prepr.io/ PREPR_TOKEN= ``` ## Laravel local caching To make use of the caching feature of Laravel, add the following parameters to your .env file. ```bash filename=".env" copy PREPR_CACHE=true PREPR_CACHE_TIME=1800 ``` ## Making your first request Let's start with getting all content items from your Prepr environment. ```php copy path('publications') ->query([ 'fields' => 'items' ]) ->get(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` To get a single content item, pass the ID to the request. ```php copy path('publications/{id}', [ 'id' => '1236f0b1-b26d-4dde-b835-9e4e441a6d09' ]) ->query([ 'fields' => 'items' ]) ->get(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` ### Override the AccessToken in a request The authorization can also be set for one specific request `->url('url')->authorization('token')`. ## Autopaging ```php copy $apiRequest = (new Prepr) ->path('publications') ->query([ 'limit' => 200 // optional ]) ->autoPaging(); if($apiRequest->getStatusCode() == 200) { dump($apiRequest->getResponse()); } ``` ## Create, Update & Destroy ### Post ```php copy $apiRequest = (new Prepr) ->path('publications') ->params([ 'body' => 'Example' ]) ->post(); if($apiRequest->getStatusCode() == 201) { dump($apiRequest->getResponse()); } ``` ### Put (Update) ```php copy $apiRequest = (new Prepr) ->path('publications') ->params([ 'body' => 'Example' ]) ->put(); if($apiRequest->getStatusCode() == 200) { dump($apiRequest->getResponse()); } ``` ### Delete ```php copy $apiRequest = (new Prepr) ->path('publications/{id}',[ 'id' => 1 ]) ->delete(); if($apiRequest->getStatusCode() == 204) { // Deleted. } ``` ### Multipart/Chunk upload - Option 1 ```php copy use Illuminate\Support\Facades\Storage; $source = Storage::readStream('image.jpg'); $apiRequest = (new Prepr) ->path('assets') ->params([ 'body' => 'Example', ]) ->file($source); if($apiRequest->getStatusCode() == 200) { dump($apiRequest->getResponse()); } ``` - Option 2 ```php copy use Illuminate\Support\Facades\Storage; $source = Storage::get('image.jpg'); $apiRequest = (new Prepr) ->path('assets') ->params([ 'body' => 'Example', ]) ->file($source, 'image.jpg'); if($apiRequest->getStatusCode() == 200) { dump($apiRequest->getResponse()); } ``` ### Debug For debug you can use `getRawResponse()` Source: https://docs.prepr.io/laravel/laravel-rest-provider --- # PHP + Prepr GraphQL SDK This package is an SDK for the GraphQL API. ## Basics The SDK on [GitHub](https://github.com/preprio/php-sdk) Minimal PHP version: `^8.2` Requires `GuzzleHttp ^7.7.0` For Laravel projects we recommend using the Laravel providers for [REST](https://github.com/preprio/laravel-rest-sdk) or [GraphQL](https://github.com/preprio/laravel-graphql-sdk). ## Installation You can install the SDK as a composer package. ```bash copy composer require preprio/php-graphql-sdk ``` ## Making your first request Let's start with getting some content items from your Prepr environment. ```php copy rawQuery('{ Posts( limit : 30 ) { items { _id _slug title } } }') ->request(); print_r($apiRequest->getResponse()); ``` In the example above, we wrote all of our arguments inside the query string. However, in most applications, the arguments to fields will be dynamic. To add these properties, use the `variables` method. ```php copy rawQuery('query ($search : String) { Posts(where: { _search : $search }) { items { title } } }') ->variables([ 'search' => "amsterdam", ]) ->request(); print_r($apiRequest->getResponse()); ``` ## Using query files If you saved your GraphQL queries to a static file, you can use the following method to execute those: ```php copy query('query_file.graphql') ->request(); print_r($apiRequest->getResponse()); ``` ## Adding headers In some cases, you may need to add headers to your request. For example, when using Prepr personalization with the `Prepr-Customer-Id` header. The example below shows how to add extra headers to the requests. ```php copy headers([ 'Prepr-Customer-Id' => 'your-customers-session-or-customer-id' ]) ->request(); print_r($apiRequest->getResponse()); ``` ## Debug Errors With `$apiRequest->getRawResponse()` you can get the raw response from the Prepr API. Source: https://docs.prepr.io/php/php-graphql-sdk --- # PHP + Prepr REST SDK This package is an SDK for the REST API. ## Basics The SDK on [GitHub](https://github.com/preprio/php-sdk) Minimal PHP version: `^8.2` Requires `GuzzleHttp ^7.7.0` For Laravel projects we recommend using the Laravel providers for [REST](https://github.com/preprio/laravel-rest-sdk) or [GraphQL](https://github.com/preprio/laravel-graphql-sdk). ## Installation You can install the SDK as a composer package. ```bash copy composer require preprio/php-rest-sdk ``` ## Making your first request Let's start with getting some content items from your Prepr environment. ```php copy path('content_items') ->query([ 'fields' => 'items' ]) ->get(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` To get a single content item, pass the ID to the request. ```php copy path('content_items/{id}', [ 'id' => '1236f0b1-b26d-4dde-b835-9e4e441a6d09' ]) ->query([ 'fields' => 'items' ]) ->get(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` ### Auto paging results To get all resources for an endpoint, you can use the auto paging feature. ```php copy $apiRequest ->path('content_items') ->query([ 'limit' => 200 // optional ]) ->autoPaging(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` ### Override the AccessToken in a request The authorization can also be set for one specific request `->url('url')->authorization('token')`. ### Post ```php copy $apiRequest ->path('content_items') ->params([ 'body' => 'Example' ]) ->post(); if($apiRequest->getStatusCode() == 201) { print_r($apiRequest->getResponse()); } ``` ### Put ```php copy $apiRequest ->path('content_items') ->params([ 'body' => 'Example' ]) ->put(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` ### Delete ```php copy $apiRequest ->path('content_items/{id}',[ 'id' => "398402d-dd-asd-ads3343dad" ]) ->delete(); if($apiRequest->getStatusCode() == 204) { // Deleted. } ``` ### Multipart/Chunk asset upload ```php copy $apiRequest ->path('assets') ->params([ 'body' => 'Example', ]) ->file('/path/to/file.txt') ->post(); if($apiRequest->getStatusCode() == 200) { print_r($apiRequest->getResponse()); } ``` ### Debug Errors With `$apiRequest->getRawResponse()` you can get the raw response from the Prepr API. Source: https://docs.prepr.io/php/php-rest-sdk --- # Getting started with the Prepr GraphQL API *This guide shows you how to make your first request to fetch data from the Prepr GraphQL API in three easy steps.* ## Making your first API request That’s it. You’ve made your first call to the Prepr GraphQL API. ## What's next? You can [try out your GraphQL queries](/graphql-api/test-queries) using the *Apollo Explorer* tool. To learn more about the Prepr GraphQL API, check out the following resources: - [API basics](/graphql-api/api-basics) - [Authorization](/graphql-api/authorization) - [Caching](/graphql-api/caching) Source: https://docs.prepr.io/graphql-api/get-started --- # Testing your queries *This article helps you test your GraphQL queries on actual Prepr content using the *API Explorer* tool.* Prepr provides you with an interface based on the [*Apollo Explorer*](https://www.apollographql.com/tutorials/lift-off-part1/06-apollo-explorer) to test your requests before adding them to your web app. Within the API Explorer, you can write and validate your GraphQL queries, make a test run of the queries, and receive responses from the Prepr API straightaway. You can open the API Explorer in two ways. **From the Access token details page:** 1. Click the icon and choose the **Access tokens** option to view all access tokens. Click the desired access token to open its details. ![GraphQL production access token example](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) 2. On the **Access token details** page, click the **Open in API Explorer** link under the *API URL* field. **From the Content item details page:** 1. Navigate to the **Content** tab and click the desired content item to open its details. ![Content item details page](https://assets-site.prepr.io/16gpaz682khf//content-item-detail-open-in-api-explorer.png) 2. Click the icon and choose the **Open in API Explorer** option. Whichever option you choose, you’ll be redirected to the API Explorer interface like in the image below. ![API Explorer overview](https://assets-site.prepr.io/w_1920/6x6ziit90z5f-api-explorer-overview.png) Your API endpoint URL and schema will be registered in the API Explorer automatically, so you are ready to compose your query. ![Using the API Explorer gif](https://downloads-site.prepr.io/viamyt3e7wp-using-the-api-explorer.gif) 1. Use the **Operation** pane to compose a query. 2. On the left of the **Operation** pane, you will see the **Documentation** pane that shows all the fields and arguments available in your schema. Click the *plus icon* next to an element to add it to your query. 3. *(Optional)* In the lower part of the **Operation pane**, there are two additional tabs – **Variables** and [Headers](/graphql-api/api-basics#the-headers), where you can specify dynamic arguments and key-value pairs accordingly. 4. Once you’ve built your query, click the **Run** button. 5. Check the API response in the **Response** pane on the right. The response is available in both an interactive JSON and table format. You can also copy the response to your clipboard, download it as a CSV, or download the JSON. 6. If the query results meet your needs, copy the query to implement it in your front end easily. Source: https://docs.prepr.io/graphql-api/test-queries --- # API basics *This article takes you through the basics of the Prepr GraphQL API.* ## The API URL The GraphQL endpoint (*API URL*) looks like the URL below: `https://graphql.prepr.io/` When you add an environment, Prepr provides two API endpoints by default, *GraphQL Production* and *GraphQL Preview*. The *API URL* value for each of these is the same for any operation you perform. Check out the [Authorization doc](/graphql-api/authorization) for more details. ## The HTTP method In general, the *Hypertext Transfer Protocol (HTTP)* is how your application and the server communicate. To call the GraphQL API, you will need to use the HTTP `POST` method with the `application/json` content type to process larger queries and to send the variables and an operation name along with the query. ### Using `GET` instead of `POST` Keep the following points in mind when deciding on the HTTP method: - Consider using the `GET` method only if `POST` doesn't work in your environment. - While our GraphQL server supports `GET` for queries, it’s best to keep in mind that lengthy query strings can exceed URL length limits imposed by browsers and CDNs. - `GET` can help with HTTP caching, but be cautious with complex operations. ## Headers You can include some HTTP headers in the request, in other words, the key-value pairs to specify the request body format or additional information about the API request. The GraphQL API supports the following list of HTTP headers: ||Value| Usage| |-----|-----|----| |`Prepr-Customer-Id`|*Customer ID* or *Reference ID* of a web app visitor. You can use the `__prepr_uid` cookie to set this value.| The API uses this ID to determine which [adaptive content](/personalization/setting-up-personalization) or [A/B test variant](/ab-testing/setting-up-ab-testing) to return in the response.| |`Prepr-Visitor-IP`|IP address of the web app visitor.|The API uses this value to determine the current IP-based Geolocation of the web app visitor. It's a more accurate value when the request is made server-side.| |`Prepr-Context-utm_source`|The UTM source of the web app visitor.|Prepr uses this value to set the *UTM source tag* for the matching customer profile. If no customer profile exists yet, the API uses this value to determine which adaptive content to return in the response for a matching [UTM tag segment](/personalization/managing-segments#campaigns).| |`Prepr-Context-utm_medium`|The UTM medium of the web app visitor.|Prepr uses this value to set the *UTM medium tag* for the matching customer profile. If no customer profile exists yet, the API uses this value to determine which adaptive content to return in the response for a matching [UTM tag segment](/personalization/managing-segments#campaigns).| |`Prepr-Context-utm_term`|The UTM term of the web app visitor.|Prepr uses this value to set the *UTM term tag* for the matching customer profile. If no customer profile exists yet, the API uses this value to determine which adaptive content to return in the response for a matching [UTM tag segment](/personalization/managing-segments#campaigns).| |`Prepr-Context-utm_content`|The UTM content of the web app visitor.|Prepr uses this value to set the *UTM content tag* for the matching customer profile. If no customer profile exists yet, the API uses this value to determine which adaptive content to return in the response for a matching [UTM tag segment](/personalization/managing-segments#campaigns).| |`Prepr-Context-utm_campaign`|The UTM campaign of the web app visitor.|Prepr uses this value to set the *UTM campaign tag* for the matching customer profile. If no customer profile exists yet, the API uses this value to determine which adaptive content to return in the response for a matching [UTM tag segment](/personalization/managing-segments#campaigns).| |`Prepr-Hubspot-Id`|HubSpot ID (cookie value) of a website visitor when you've set up the HubSpot pixel in your front end. |The API uses this ID to determine which adaptive content to return in the response for a matching [HubSpot segment](/personalization/managing-segments#hubspot).| |`Prepr-Segments`| Used for [Visual Editing](/project-setup/setting-up-visual-editing#enable-segment-and-ab-test-switches). The `_id` of a specific segment. You can use the `prepr_preview_segment` query parameter in the URL to set this value.| The API uses this value to determine which [adaptive content](/personalization/setting-up-personalization) to return in the response.| |`Prepr-ABTesting`|Used for [Visual Editing](/project-setup/setting-up-visual-editing#enable-segment-and-ab-test-switches). A value of `A` or `B`. You can use the `prepr_preview_ab` query parameter in the URL to set this value.| The API uses this value to determine which [A/B test variant](/ab-testing/setting-up-ab-testing) to return in the response.| ## Body Include a query string with the following properties in the body of the request you send to the API: - **query** — the full GraphQL query containing the operation type (currently, only the query type is supported), the types & fields requested, and any variables included. - **operationName** — optional, but if included, must be present in the query. - **variables** — optional if there are no variables included in the query. See an example request below with the following variables: ```json copy { "postId": "c85aa36b-8796-4f0d-955e-b317f7f905a2", "locale": "en-US" } ``` The GraphQL API will validate and execute this query string and return a response in JSON format. When a query contains a mistake, the API returns an error message in the response. Read more about possible [statuses and errors](/graphql-api/statuses-errors). Source: https://docs.prepr.io/graphql-api/api-basics --- # Authorization *In this article, you’ll learn how to get access to the Prepr GraphQL API.* ## Access tokens To query environment content using the GraphQL API, you need to have a valid access token. Prepr supports multiple access tokens with different [permissions](/graphql-api/authorization#permissions) per environment. During the initial setup of an environment, Prepr automatically generates two unique access tokens — *GraphQL Production* and *GraphQL Preview*. ![Access tokens](https://assets-site.prepr.io/ej6satg2vsl//access-tokens-production-and-preview.png) The access tokens are included in the GraphQL endpoint URLs as follows: `https://graphql.prepr.io/` You can find the *API URLs* in your Prepr environment by clicking the icon, choosing the **Access tokens** option and clicking the desired access token. ![access token](https://assets-site.prepr.io/l24g7i7rwmf//graphql-access-token.png) You can generate a new access token anytime, for example, when adding a new front-end application or [upgrading to the latest API version](/graphql-api/upgrade-guide). ## Permissions For each access token you create, you need to determine what kind of content it needs access to. Prepr uses *permissions* for that. Permissions allow you to limit a token’s access to your environment content based on [content item statuses](/content-management/collaboration#workflow-status). For example, the default API endpoints have the following permissions: - The *GraphQL Production* token allows you to retrieve all published content items. - The *GraphQL Preview* token allows you to retrieve content items in all available statuses, including *To do*, *In progress*, *Review*, *Done*, and *Published*. You can create a new access token anytime and define token permissions according to your specific needs. ![Permissions](https://assets-site.prepr.io/1x3g37nh9h5s//graphql-access-token-permissions.png) Source: https://docs.prepr.io/graphql-api/authorization --- # Caching *Caching helps applications perform faster and cost less. In this article, you'll learn about the Prepr API caching approach.* All Prepr content is served by our globally distributed *content delivery network (CDN)*. When you send your first request to the API, its response is cached in an edge cache location of our partner [Fastly](https://fastly.com). If you repeat the same request, you get a cached response from the CDN within 12 ms (on average). With Prepr’s CDN cache, you can deliver a great web performance and user experience, particularly: - Reduce the load time of your page. - Provide a more secure network. - Ensure maximum availability and accessibility to your website. Learn more about the Prepr API caching approach below. ## Two-level caching strategy The Prepr API uses a multi-tiered caching approach that serves as real-time load-balancing between multiple CDNs. Incoming requests are processed by the edge servers in locations closer to the end user. When those edge servers don't have a cached response for the query, they will retrieve information from our main cache layer in the Amsterdam Data Center before eventually retrieving it from Prepr's backend servers. As a result, the two-level caching strategy significantly reduces the distance the information has to travel. ## Smart cache invalidation Our CDN cache uses *Smart Invalidation*, which allows removing stale cache entries before their normal expiration time (also known as Time to live - TTL). The *Smart Invalidation algorithm* continuously processes and analyzes all queries that pass through the CDN edge locations. Whenever [content items](/content-management/managing-content/managing-content-items) or [underlying schemas](/content-modeling/fundamentals#what-is-a-schema) change in Prepr, the edge servers automatically invalidate the associated data from the cache. This guarantees that the most current data is always served to your website visitors. ## No rate limits No limits are enforced on requests that hit Prepr’s CDN cache. It means these requests don’t count toward the rate limits, and you can make unlimited cache hits. ## Caching headers Prepr sets the following HTTP headers on all API responses by default: | header attribute | description | | ------------- |-------------| | X-Prepr-Cache | Indicates whether the request was a HIT or a MISS. [Read more](https://developer.fastly.com/reference/http/http-headers/X-Cache/) | | X-Prepr-Identity | Indicates the cache servers processing the response. [Read more](https://developer.fastly.com/reference/http/http-headers/X-Served-By/) | | X-Prepr-Region | Indicates a region where the response is processed. | ## Purging cache When you need a real-time sync of new content or you need to clear old versions of data in the case of a manual deployment, you can manually purge cache for an access token by doing the following: 1. Click the and choose the **Access tokens** option to view all the access tokens. 2. Click the access token for which you want to purge the cache and click the **Purge token cache** button. 3. Then click the **Purge cache** to confirm your decision. ![confirm purge](https://assets-site.prepr.io//3gwhvm7r89pr-confirm-purge.png) ## Read after write consistency When you get a successful response for a mutation request, changes are persisted in Prepr. It is important to note that some changes are not visible immediately after the update. If you fetch content with a GraphQL API request right after a mutation with the REST API, you might get back stale content. Because, when you create, delete or update content the request is distributed around the globe with a short delay. Source: https://docs.prepr.io/graphql-api/caching --- # Statuses and errors *This article describes the standard HTTP status and error codes the GraphQL API returns when resolving a query.* ## HTTP response status codes The GraphQL API uses standard HTTP status codes to indicate whether a request is successful or not. In general, status codes within the *2xx range* indicate a successful request. When you receive an HTTP status code different from *2xx*, then you probably have one of the following issues: - Client-side validation problems like an invalid query argument or access token (*4xx HTTP codes*). - Server or connection problems (*5xx HTTP codes*). | Status code | Description | |-----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **200 OK** | The request is successful. However, the API response might contain an error. For example, if your query is too complex or contains typos, etc. | | **401 Unauthorized** | The access token is invalid. | | **405 Method Not Allowed** | The requested HTTP method is not supported for the specified resource. | | **412 Precondition failed** | There is an issue with the query, for example, there are non-UTF characters in the query or the actual query is too large. In the body of the response, you'll see something like `Query could not be compressed. Query limit is 27500 but length was 28196.` This means the actual query is too big and you might need to [compress](https://www.npmjs.com/package/graphql-query-compress) it. | | **429 Too many requests** | You have exceeded the rate limit. | | **5xx Internal Error or Service Unavailable** | Something went wrong on the Prepr server side. Try your request again after a few seconds. | | **5x3 Service Unavailable** | In most cases this requests exceeds the edge rate limits. Try your request again after a few seconds. | ## Example GraphQL errors The GraphQL API also verifies if a request is syntactically correct and mistake-free in the context of a given GraphQL schema. When a query contains a mistake, an error message can be returned in the response. See some known GraphQL errors below. **Example 1.** When a query size exceeds the 8kb limit, you’ll see the following error message: ```json copy { "errors": [ { "message": "Syntax Error: Unexpected ", "extensions": { "category": "graphql" }, "locations": [ { "line": 1, "column": 1 } ] } ] } ``` Prepr limits a query size to a maximum of 8 kb to increase data retrieval performance from the [cache](/graphql-api/caching). The limit cannot be adjusted at the moment. We recommend that you use fragments for large requests. Alternatively, some libraries will automatically remove unnecessary whitespace and comments, like [GraphQl Query Compress](https://www.npmjs.com/package/graphql-query-compress). **Example 2.** When a wrong typecast is specified in a query (*Int/String/etc.*), the GraphQL API returns the following error message: ```json copy { "errors": [ { "message": "Variable \"$id\" of type \"Int\" used in position expecting type \"String\".", "extensions": { "category": "graphql" }, "locations": [ { "line": 1, "column": 21 } ] } ] } ``` Follow the tips in the error message to resolve an issue. **Example 3.** When a request contains a field that is not available in the schema definition, the following error message will be returned: ```json copy { "errors": [ { "message": "Cannot query field \"content_ref\" on type \"Blog\".", "extensions": { "category": "graphql" }, "locations": [ { "line": 5, "column": 3 } ] } ] } ``` Check out your schema definition and update the requested field name to the correct one. **Example 4.** When a typo is made in a property name, you’ll get the following error message: ```json copy { "errors": [ { "message": "Cannot query field \"id\" on type \"Blog\". Did you mean \"_id\"?", "extensions": { "category": "graphql" }, "locations": [ { "line": 3, "column": 8 } ] } ] } ``` Follow the tips in the error message to resolve an issue. ## Invisible unicode characters in the API response If you see invisible unicode characters in the API response, it means the **Enable edit mode** is checked in the access token you're using. ![Preview access token - enable edit mode](https://assets-site.prepr.io/46aks93acmht//preview-access-token-enable-edit-mode.png) These characters are Stega-encoded strings which produce invisible output to allow content editors to use the [Vercel **Edit Mode**](/project-setup/setting-up-previews#editing-content-directly-with-vercel-content-link). When you turn on edit mode in an access token, Stega-encoding serializes metadata into invisible UTF-8 encoded characters and appends them to string values. ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) Source: https://docs.prepr.io/graphql-api/statuses-errors --- # GraphQL API diagnostic tools *This article shows you how to use a couple of GraphQL API diagnostic tools to help solve some common issues.* ## Debugging a schema If you're unable to see your schema in a schema introspection tool like *Apollo API Explorer* in Prepr or when making requests through Postman, it's useful to run an endpoint diagnosis to verify the schema is valid. In this case, you can debug the schema as follows: 1. Use an API diagnostic tool to debug the broken schema by executing the following command in the terminal: ```bash copy npx diagnose-endpoint@1.1.0 --endpoint="" ``` 2. Replace the placeholder value `` with the *API URL* of the access token from Prepr. You know that the schema is well-formed when you get the message: `Could not find any problems with the endpoint.` Otherwise, the tool displays an error message like one of the following: - `⚠️ Invalid schema from introspection: Union type AllModels must define one or more member types.` -> This means your schema is completely empty. - `Cannot query field "fieldName" on type "TypeName".` - `Expected type "TypeName", found "InvalidType"` - `Type "TypeName" was defined more than once.` The detailed error message helps you pinpoint the entity or field that resulted in the corrupted schema. ## Checking the difference between two schemas The [*GraphQL Schema Diff* tool](https://github.com/fabsrc/graphql-schema-diff) identifies differences between two GraphQL schemas, making it useful for the following cases: - Before [syncing two schemas](/development/working-with-cicd/syncing-a-schema) across environments, it's a good idea to check for differences that could cause breaking changes before you start. - Comparing two different API versions for the same environment, for example, when upgrading your API. Run the `graphql-schema-diff` tool to view differences between two schemas or two API versions as follows: 1. Install the *GraphQL Schema Diff* tool by executing the following command in the terminal: ```bash copy npm install -g graphql-schema-diff ``` 2. Once installed, you can run the tool with the following command: ```bash copy graphql-schema-diff -s ``` 3. Replace the placeholder values `` and `` with the *API URL* of the access tokens for each schema you want to compare. You'll get a similar result to the image below. ![schema diff report](https://assets-site.prepr.io/3zbi56760wg7//schema-diff-changes-report.png) We trust that these diagnostic tools help you debug similar API-related issues more easily. Don't hesitate to reach out to [Prepr support](https://prepr.io/support) for questions or to add your own favorite diagnostic tools to this list. Source: https://docs.prepr.io/graphql-api/diagnostic-tools --- # Versioning & Upgrade guide *Learn more about our version support policy and the steps you need to take to upgrade your app to a newer API version.* When backwards-incompatible changes are made to the API, we release a new, dated version. The current version is `2025-10-07`. For information on all API updates, view our upgrade guide below. By default, requests made to the API use your access token's default API version (you can see that version in the Prepr UI) unless you override it by setting the `Prepr-Version` header. ## Support policy Prepr guarantees technical assistance and security updates for each new version of the GraphQL API for at least 24 months. Please note that **we do not change your API version automatically to avoid breaking your code**. Once you are ready to upgrade, please follow the instructions below. ## How to upgrade to a newer GraphQL API version Your API version controls the API behavior you see (for example, how your schema is generated and what fields you can request). When a major or breaking change is introduced to the API, Prepr releases a new version based on the release date. In this case, we encourage our customers to upgrade their GraphQL API versions as soon as possible. To upgrade to a newer GraphQL API version, you need to generate a new access token for your Prepr environment as follows: 1. Click the icon and choose the **Access tokens** option to open the access tokens page. 2. Click the **Add access token** button. ![Create a new access token](https://assets-site.prepr.io/3wkskssa3gmf//adding-new-access-token.png) 3. Enter the *Name* for the new access token. For example, the access token you use to retrieve all published content items can be titled *Published*. If you want to preview the unpublished items on your staging site, consider creating an additional *Preview* token. 4. Next, define permissions for this access token under the *GraphQL Permissions* section. Permissions allow you to choose which content item statuses are accessible for an access token. [Read more about GraphQL permissions](/graphql-api/authorization#permissions). 5. Click **Save** to confirm the settings. Once you've created a new access token, you'll notice the new API version indicated on the **Access tokens overview** page. By default, the new access token uses the latest GraphQL API version on the token generation date. ## Released GraphQL API versions You can check out the previous Prepr GraphQL API releases below. | version | release date | end-of-life on | |-----------------|--------------|----------------| | 2025-10-07 | 2025-10-07 | t.b.a | | 2025-05-27 | 2025-05-27 | 2027-10-07 | | 2024-12-05 | 2024-12-05 | 2027-05-27 | | 2024-10-04 | 2024-10-04 | 2026-12-05 | | 2024-06-12 | 2024-06-12 | 2026-10-04 | | 2024-05-15 | 2024-05-15 | 2026-06-11 | | 2024-03-26 | 2024-03-26 | 2026-05-15 | | 2024-01-31 | 2024-01-31 | 2026-03-26 | | 2023-11-02 | 2023-11-06 | 2026-01-31 | | 2023-06-30 | 2023-06-30 | 2025-11-06 | | **END OF LIFE** | | 2023-04-17 | 2023-04-17 | 2025-06-30 | | 2023-02-09 | 2023-02-09 | 2025-04-17 | | 2023-01-10 | 2023-01-10 | 2025-01-10 | | 2022-08-15 | 2022-08-15 | 2024-08-15 | | 2022-03-20 | 2022-03-20 | 2024-03-20 | | 2022-02-15 | 2022-02-15 | 2023-06-01 | | 2021-11-29 | 2021-11-29 | 2022-11-29 | | 2021-09-27 | 2021-09-27 | 2022-09-27 | ### Version `2025-10-07` **What's new** - `DefaultLocale` is added as a root query field, returning the environment's default locale. - `_locale` is added to the Interface `Model` - `_locales` is added to the Interface `Model` **What's changed** - The type of the `items` field of the ContentItems query has been changed from Union Type "AllModels" to non-null Interface type `Model`. Previously, querying required inline fragments on `Model`, but now interface fields can be accessed directly for a cleaner query structure. ```graphql copy # Before query { ContentItems { items { ... on Model { _id, _created_on } } } } # Since 2025-10-07 query { ContentItems { items { # Interface fields can now be queried without the ... on Model prefix: _id, _created_on } } } ``` - The `total` field of the ContentItems query is now marked as non-null. - If in a query only the field `_localizations` is passed, the fields from inside that field will be set as the resolved fields for the query. - Input validation for the field type `_DateTime` has changed and will now validate that microseconds (if set) are 0. - All fields of type `Tag` are now marked as non-null. - Added support for the `@oneOf` directive on input objects, to be applied in upcoming releases. ### Version `2025-05-27` **What's new** - Previously, you could add personalization and A/B test content only to a stack field directly included in the model. We've enhanced the *Stack* field to allow personalization and A/B test content at any level in the content structure. These include stack fields in components and within dynamic content fields. - It's now possible to add a *Dynamic content* field to a component to add rich content sections to your section-based pages. For example, to publish a guide with your chosen styling. - You can now access a default query to retrieve the locales available in your environment, making it easier for you to implement localization switches in your front end. - We added support for the *Tags* field type to components. **What's changed** - We've changed the default sorting on `string` fields to be case-insensitive. ### Version `2024-12-05` **What's new** - Remote Source types now have a new default field `_json`. This field returns the raw data content retrieved from the remote source. - Added a new Scalar Type `Json` to support the new field type on the Remote Source types. - Remote Source fields can now be configured as a single-item field. - Added `BlueskyPost` and `ThreadsPost` types for new supported embeds. - Model Stack fields can now also be filtered on the Typename of a referenced component. - You can now filter content items by the Model Asset field for a specific asset or if the Asset field is filled. **What's changed** - Model Stack fields filtered on a Content Item ID can now also filter if the component is referenced in a component (or sub-component) field. ### Version `2024-10-04` **What's new** - Stack & Reference fields can now be configured as a single-item field. This removes unnecessary arrays when using the field with a single element. Support for this feature has been added to all previous versions up to version `2023-02-09`. **What's changed** - A/B tests without a `B` variant will now return no element for B targeted visitors, instead of always defaulting to `A`. ### Version `2024-06-12` **What's new** - The Context Type is now extended with a new field `variant_key`. In the upcoming release of the Prepr UI, this key will make tracking conversions on A/B tests or Personalizations much easier. - In preparation for the upcoming release of custom events, a new system field `_event` has been added to the schema. This field, which expects a name argument, return a count of events from the specified type. - For existing Prepr environments ENUM types can now be set to legacy mode (returning as a STRING instead of a native ENUM type). **What's changed** - The specific event counter fields (`_comments`, `_purchases`, `_votes`, `_click-throughs`, `_shares`) have been removed from the default schema. Instead, you can use the new field `_event(name: Purchase)` to achieve the same result. - If a locale is requested that is not set up in your Prepr environment, it will now throw a clear error. - The `_Event` enum now also will hold all custom create event types. - The input on filtering on Customer Relation has changed from argument `_type` to `event`. - The Enum `CustomerRelationType` has been removed from the schema. - Locales in the `_localizations` field are now consistently returned in alphabetical order (A-Z). This replaces the previous behavior where locales were returned in a unpredictable order. ``` // Before 2024-06-11 query { ContentItems( where: { _typename_any : ["Post"] _customer_relation : { id : "ad5714b0-dea5-46b3-9386-0f109ebbe29b", _type : BOOKMARKED } } ) { // } } ``` ``` // After 2024-06-12 query { ContentItems( where: { _typename_any : ["Post"] _customer_relation : { id : "ad5714b0-dea5-46b3-9386-0f109ebbe29b", event : Bookmark } } ) { // } } ``` ### Version `2024-05-15` **What's new** We are very excited to bring you the long-awaited feature to add fields to Assets. It is now possible to define your own fields to keep track of asset-specific info like Copyright or Source in addition to the core asset fields for the title, description and the author. Now, it's also possible to enable localization for your assets. This means your editors can enter information about assets in the locale that is relevant for them. **What's changed** - If an API version is specified by using the HTTP header `Prepr-Version` and set to a non-existing version, this will now generate an exception. ### Version `2024-03-26` **What's new** We are thrilled to introduce the long-awaited Enumerations feature. We've broadened the schema to allow you to create your own enumerations and use them in any model or component using the List field. The ability to reuse a single enumeration across multiple models and components results in a cleaner schema. **What's changed** - All list fields are update to use the new Enumerations feature. The response type of all list fields is changed from String or String! to the matching enumeration type. - All filters on list fields are updated from String to the matching enumeration type. - Please review your migrated ENUM lists for entries that commence with a numerical character, as ENUM values do not permit starting with an integer. ### Version `2024-01-31` **What's new** - Stack fields are now available in components, making your schema's way more flexible. - Filtering on content relations is now extended to Stack fields. - We added new filters for all content reference, remote content and slug fields. **What's changed** - **Slug NULL filtering**\ If null is passed to the \_slug\_any filter, this release will return all content items without a set slug. The behavior until this version was that all items were returned. ```graphql copy query { Posts( where: { _slug_any : null } ) } ``` - **Slug ANY filtering**\ If an empty list is passed to the \_slug\_any filter, this release will return all content items with a set slug. The behavior until this version was that all items were returned. ```graphql copy query { Posts( where: { _slug_any : [] } ) } ``` - **Content reference filtering**\ If an empty object is passed to any reference filter, this release will return all content items with at least one referenced item. The behavior until this version was that all items were returned. ```graphql copy query { Posts( where: { sections: {} } ) } ``` ### Version `2023-11-02` **What's new** - **Introducing Strict Mode** *Strict Mode is released in public beta, if you have any feedback on this new feature, please let us know.* Strict Mode means you get more accurate and reliable TypeScript types from your GraphQL schema. When you enable Strict Mode, the resulting GraphQL type will be `String!`, for example, instead of `String`. When the exclamation mark is omitted then it means the field is a string that will never be null. In other words, code generators produce the TypeScript type of `string` instead of `string | null | undefined`. That means you won't have to handle those additional cases in your front end, and TypeScript won't complain if you write things like `author.name.toLowerCase()`. **Some more** - All model Types now include a new field `_last_published_on`. This field returns the timestamp of the last time the item was published. - Union reference fields can now also be filtered based on the reference `ID`, `slug` of `typename`. **What's changed** - If you enable Strict Mode, all fields in your model and components that are marked as required are now marked as non-null. - For all types (except Asset) the `_type` field has been removed, use `__typename` instead. - Collection queries now strictly enforce a pagination limit of 100. **Non-Null Markings** - For the types FacebookPost, InstagramPost, SoundCloudPost, SpotifyPlaylist, TikTokPost, TwitterPost and VimeoPost the `url` field is now marked as non-null to match the ApplePodcast type. - For all model types, the event counters are now marked as non-null Integer fields. - For the types \_DateRange, \_DateTimeRange and BusinessHours all fields are now marked as non-null. - The BusinessHoursPeriod type fields `open_day`, `open_time`, `close_day`, `close_time` and `is_closed` are now marked as non-null. ### Version `2023-06-30` **What's new** - In this release, we've added a new recommendation algorithm to the API. All models now have a [**People Also Viewed** recommendation query](/graphql-api/personalization-recommedations-people-also-viewed-content). - An asset field can now be configured as a single-asset field. This removes unnecessary arrays when using an asset field with a single asset. - The introduction of nested components has made content modeling in Prepr even more powerful. You can now [embed one component into another](/content-modeling/managing-components#create-a-nested-component), creating a parent-child relationship within a component. - For complex filtering, we've added an `OR` filter to the collection filters. - A new `not_contains` filter is available for all Text fields. **What's changed** - Internal links in the text will now remove the `` tags by default. If you need the plain text, change the field in your query from `body` to `text`. New formatted response: ```graphql copy query { "data": { "Page": { "dynamic_field": [ { "body": "

Hi1

" } ] } } } ``` Response in version `2021-09-27`: ```graphql copy query { "data": { "Recipe": { "dynamic": [ { "body": "Hi1" }, { "body": "H2" } ] } } } ``` Source: https://docs.prepr.io/graphql-api/upgrade-guide --- # Introduction to the GraphQL API schema *The GraphQL API uses a schema to describe which data types are available in your system and how you can query them. From this article, you’ll learn how the Prepr GraphQL API schema is generated and how you can use it to integrate content into your web app.* ## Schema generation A schema is the definition of the content structure for your web app. In Prepr, a schema consists of several content types: *models*, *components*, and *remote sources*. Each of these content types comes with corresponding *fields*. Prepr provides you with the GraphQL API you can use to integrate the content into your application. For each content type in Prepr, the GraphQL API creates a corresponding [GraphQL type](https://graphql.org/learn/schema/), including available fields. These types describe the set of possible data you can query from Prepr. Each of the GraphQL types and GraphQL fields must have a unique name as follows: - The *Type name* is in pascal-case with only alphanumeric characters. - The *Field name* is in lower camel-case with alphanumeric characters and underscores only. Some Type names are reserved for metadata or default types. You can check them out in [Reserved terms](/graphql-api/api-schema#reserved-terms). The GraphQL API schema is generated automatically at request time, so it’s always current. We recommend [browsing a schema with an API Explorer](https://studio.apollographql.com/sandbox/explorer) to get a complete overview of GraphQL type definitions and filtering options applicable to your setup. Also, you can [inspect your schema using GraphQL Introspection](https://graphql.org/learn/introspection/). Find more information about supported GraphQL types and fields by following the links below: - [Models and components](/graphql-api/schema-models) - [System fields](/graphql-api/schema-system-fields) - [Field types](/graphql-api/schema-field-types) ## Querying a schema Prepr provides an interface based on the Apollo Explorer to test your requests before integrating them into production. Within the API Explorer, you can write and validate your GraphQL queries, make a test run of the queries, and receive responses from the Prepr API straightaway. Find more information in [Draft your queries](/graphql-api/test-queries). Once you run a query, it will be validated and executed against the GraphQL API schema. The GraphQL API uses standard HTTP status codes to indicate whether a request is successful. Check out [Statuses and errors](/graphql-api/statuses-errors) for more details. ## Reserved terms The following *Type names* are default types and reserved for metadata: - `Boolean` - `BusinessHours` - `Context` - `Coordinates` - `CoordinatesCircle` - `DateTime` - `Directive` - `Enum` - `EnumValueDefinition` - `Field` - `Float` - `ID` - `Int` - `Interface` - `KeyValue` - `ListOf` - `Location` - `NonNull` - `Number` - `Object` - `Paragraph` - `Query` - `Quote` - `Resource` - `Resolve` - `Scalar` - `Stack` - `String` - `Text` - `TextFormat` - `Type` - `TypeWithFields` - `Union` - `UnresolvedField` - `Asset` - `AssetAlignment` - `Assets` - `CdnFile` - `Channel` - `Component` - `ContentIntegration` - `ContentIntegrations` - `ContentItem` - `ContentItems` - `Customer` - `CustomerScalar` - `Model` - `Publication` - `Publications` - `Story` - `Tag` - `User` - `ApplePodcast` - `BlueskyPost` - `FacebookPost` - `InstagramPost` - `SoundCloudPost` - `SpotifyPlaylist` - `ThreadsPost` - `TikTokPost` - `TwitterPost` - `VimeoPost` - `YouTubePost` - `ActiveCampaignEmbed` - `HubSpotEmbed` - `PipedriveEmbed` - `TypeformEmbed` - `Event` - `NavigationItem` - `embed` - `embeds` - `item` - `items` - `slug` Including all types starting with `_` and ending with `_DESC` or `_ASC`. Using one of the reserved terms as a field name will result in a schema collision error asking you to use a different name instead. Source: https://docs.prepr.io/graphql-api/api-schema --- # Strict Mode Strict mode enforces stricter validation and adherence to the schema. You can [enable strict mode](/development/best-practices/typescript#enable-strict-mode) for your schema on an access token. If you enable strict mode on your access token only permissions with active required validation can be chosen from the permissions list. Take note of [the workflow stage for the required validation](/development/best-practices/typescript#set-workflow-stages-to-trigger-the-required-validation). In contrast to normal operation *Strict Mode* affects the associated GraphQL type. For example all required text fields in your schema will result in the GraphQL type `String!`, instead of `String`. When the exclamation mark is omitted then it means the field is a string that will never be null. In other words, code generators produce the TypeScript type of `string` instead of `string | null | undefined`. This makes the front end code cleaner and more consistent. Source: https://docs.prepr.io/graphql-api/strict-mode --- # Models & Components Prepr automatically generates the [GraphQL API schema](/graphql-api/api-schema) for your project based on models you create, including associated components, remote sources, and fields. **Models** consist of a number of fields and components and determine the structure of the content in a web app. Each model has its own unique name used for interaction with the API as described in the following table. You can find a model name by navigating to **Schema → Model settings**. |Prepr UI name | Description| |--------------------------|--------------| |**Singular name** |In pascal-case with only alphanumeric characters. For example, *NewsArticle*.| |**Plural name**| In pascal-case with only alphanumeric characters. For example, *NewsArticles*. The Plural name can not be the same as the singular. **Components** are predefined sets of fields that can be used in models or included in the *Stack field* but cannot be interacted with as an individual entry. Each component has a unique name used for interaction with the API, as the table below shows: |Prepr UI name | Description| |--------------------------|--------------| |**Type name** |In pascal-case with only alphanumeric characters. For example, *SEOTags*.| Next, check out [System fields](/graphql-api/schema-system-fields) and [Field types](/graphql-api/schema-field-types). Source: https://docs.prepr.io/graphql-api/schema-models --- # System fields Some fields are system-generated. The system fields are read-only fields that provide information about the content or any related record from the system, like a Content item ID or when a content item was created or last changed. You can recognize system fields by the prefix `_`. Please see the full list of system fields below. ## Content ### \_id `UUID` Unique identifier for each item. ### \_\_typename `string` At any point in a query `__typename` can be requested to get the name of the object type returned. ### \_environment\_id `string` Unique identifier of the Prepr environment. ### \_created\_on `ISO 8601` UTC time at which the content item was created. ### \_changed\_on `ISO 8601` UTC time at which the content item was last updated. ### \_publish\_on `ISO 8601` UTC time at which the content item is or will be published. ### \_last\_published\_on `ISO 8601` UTC time when the content item was last published. ### \_slug `string` Unique reference within a content model. ### \_read\_time `int` If the content item contains String/Text fields, a calculated read time is available. ## Localization When your Prepr environment is set-up for localization. The content model will be extended with the following fields: ### \_locale `string` Locale that is returned for this content item. ### \_locales `list of: string` List of locales that are present in the content item. ### \_localizations `list of: self` Returns the content item in all available locales. ## Personalization and A/B testing When A/B testing or personalization is enabled, the following fields are available for content items and components in the *Stack* to support options for analytics and SSR. ### \_context `self` Grouping details about A/B testing or personalization with the following fields: #### kind `string` Contains a value of `PERSONALIZATION` or `AB_TEST` #### group\_id `string` Unique identifier for each personalization and A/B test group in the *Stack* #### variant\_key `string` Prepr tracking variant key to easily collect conversion data for A/B testing or personalization. #### variant\_id `string` The ID of the personalization or A/B test variant. For personalization the value is a combination of the audience and country segments, while for A/B testing, it will have a value of `A` OR `B`. #### segments `list of: string` Contains a list of customer segment ID's. Each customer segment will have two IDs listed, the Prepr UUID and the *Customer Segment ID*. ## Remote Source specific fields ### \_json `json` This field returns the raw data content retrieved from the remote source. ## Events The total count of events that are posted to Prepr. **Note** Requesting fields listed below will reduce the cache time significantly (to aprox. 20 minutes). ### \_event(name: View) `int` Total number of specified events for this content item. ### \_views `int` Total number of View events for this content item. ### \_likes `int` Total number of Like events for this content item. ### \_bookmarks `int` Total number of Bookmark events for this content item. ### \_subscribes `int` Total number of Subscribe events for this content item. Source: https://docs.prepr.io/graphql-api/schema-system-fields --- # Field types The GraphQL schema is automatically generated based on models, components, remote sources, and fields. Prepr supports all GraphQL's default scalar types, such as *String, Int, Float, Boolean*, and some *custom types*. Each field type you add to a model has a unique name used for interaction with the API. This page lists all core field types available for your API, as well as sample queries to retrieve content for these through the API. Also, it is recommended that you [browse a schema with an API Explorer](https://studio.apollographql.com/sandbox/explorer) to get a complete overview of all field type definitions and filtering options applicable to your setup. ## Text *Text* fields return a simple string with the content of the field. In the case of an HTML text field, the string can contain basic HTML tags for the paragraph, heading, bold, italic, underline, unordered list, ordered list, link, table and alignment styles. ### Resolving internal text links The `href` value for a link to a content item is its *Slug*, for assets a download url to the file is provided. To get the content item/asset ID instead, add the HTTP header `Prepr-Resolve-Internal-Links` to your request and set it to `false`. The `href` value will now contain the content item ID prefixed with `puuid#`, assets ID's are prefixed with `auuid#`. [Clear the cache on the *Access tokens* page](/graphql-api/caching#purging-cache) after adding this header to your request. ## List (Enumeration) *List* fields return a simple string with the content of the field. The return type matches the linked *Enumeration* like in the example below. ![button type enumeration](https://assets-site.prepr.io/6vmpd0p5azsh//enumeration-example-button-type.png) ## Dynamic Content Field The Dynamic Content Editor enables editors for a next-level authoring experience. Embed videos, social media posts, maps, assets, and components to create rich content items. Check out the [Dynamic Content Field](/graphql-api/schema-field-types-dynamic-content-field) section on how to query all types of content. ## Assets Assets are photos, videos, audio files or documents that you can attach to a content item. The Asset type comes with its own set of default fields. You can add fields to the [Asset model](/content-modeling/defining-the-asset-model) and include them in your request like in the example below. **Type definition** ```graphql copy type Asset { _id: String name: String description: String url: String duration: Int # Duration in seconds width: Int height: Int mime_type: String original_name: String author: String caption: String alignment: EnumType AssetAlignment (left, center, right) # Additional Asset model fields in the default locale copyrighted: Boolean # Boolean field to mark an asset as copyrighted author_name: String # Text field to store an author name # Additional Asset model fields for other locales # If you have asset data in multiple locales, include the # localized param to get those additional fields localized: { de-DE: { # Example locale de-DE to get the German fields copyrighted : Boolean } } # Custom Enterprise only cdn_files: Union type of CdnFileType } ``` Check the sample query for retrieving the default asset fields like `_id`, `author`, `caption` and `alignment`. ### Images The GraphQL API exposes a set of image transformation and formatting options. The following table lists the most common operations. | Operation | Argument | Description | |-----------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Resize** | `width`, `height` | To change the image size.*Options:* a value in pixels. If a focal point is set, the focal point values are returned in the response when resizing an image. | | | **Crop** | `crop` | To crop a particular area of an image.*Options:* north, northeast, east, southeast, south, southwest, west, northwest, center, centre. | | **Get focal point** | `focal point` | To retrieve the focal point (`x`, `y`) value. | | **Presets** | `preset` | To retrieve cropped images generated in the Prepr Editor interface.*Options:* the name you defined for the preset you would like to retrieve. | | **Formatting** | `format` | To define image format.*Options:* jpg, png, etc. Images are served in the best format if not specified. Read more in the Automatic image optimization paragraph below. | | **Original File** | `as_file` | If true; returns the original uploaded file without any optimisation or compression. | To perform image operations, you need to pass arguments to the image URL field as shown below: #### Automatic image optimization Images are automatically served in WebP or AVIF to browsers that natively support those image formats. WebP and AVIF provide better image compression and faster page loading times than other file formats. ### Video Video files uploaded to Prepr will be stored in and played from [Mux](https://www.mux.com/) for all new Prepr accounts. You can configure streaming options for videos by including the `resolution` and `duration` attributes in your API request. Using the `cover` attribute, you can [get a video thumbnail from Prepr](/content-management/managing-assets/managing-assets#replacing-video-thumbnails). Please see an example code snippet below. To learn how to display video content in your web app, please follow our guides for [live video streaming](/development/best-practices/assets/live-video-stream) and [video files on-demand](/development/best-practices/assets/video-audio). For additional information, refer to the [Mux documentation](https://docs.mux.com/guides/play-your-videos). ### Audio Audio files uploaded to Prepr will be stored in and played from [Mux](https://www.mux.com/) for all new Prepr accounts. You can configure streaming options for your audio files by including the `resolution` and `duration` attributes in the API request. Please see an example code snippet below. To learn how to play audio content in your web app, please [follow our guidelines for audio files](/development/best-practices/assets/video-audio). ### Files Files will be available by a simple url. The following table lists optional arguments for the url field. | Argument | Description | |----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| | `inline` | If true; returns the file with the `Content-Disposition` header set to `inline`, this opens the file in the browser instead of the default download behaviour. | ### Fetching a single-asset field You can choose between using a multiple-asset or single-asset field [when adding it to a model or component](/content-modeling/field-types#assets-field), depending on the number of assets you intend to add. When querying a single-asset field, you'll receive a response similar to this: ```json copy { "data": { "Post": { "video": { "playback_id" : "fyd7tJBz01bUEsbgs7d02US01K8Tp00SB3gWn01WPneVKeCmQIM", "hls": "https://stream.mux.com/fyd7tJBz01bUEsbgs7d02US01K8Tp00SB3gWn01WPneVKeCmQIM.m3u8", "duration": 12045 } } } } ``` ### Hostnames To set up hostnames for streaming assets in your front-end application, for example, when using Nuxt/Next.JS's Image Optimization plugins or for CSP configurations), in your Prepr environment click the icon and choose **Access Tokens** to get them in the *Image and file domains* section. ![Image and file domains](https://assets-site.prepr.io/cj9qfjs5u3e//image-and-file-domains.png) ## Integer Integers are whole number, and are often used to store stock quantities, prices in cents ect. For example, here we have a product with an Integer field for quantity. ## Float Float types are fields in which you can make number entries with decimal places, for accurate calculation such as the price of an item, distance, or weight. For example, here we have a product with a Float field for price. ## Boolean For example, here we have posts with a Boolean field for premium\_only. ## Stack The Stack field is a powerful type that stores a collection of models and components useful for building web pages. This powerful type includes any personalized or A/B test group details. For more details on fetching A/B test content, check out the [GraphQL API A/B testing doc](/graphql-api/personalization-recommedations-ab-testing).\ For more details on fetching personalized content (Adaptive content), check out the [GraphQL API personalization doc](/graphql-api/personalization-recommendations-personalized-stack). ### One-to-many Our Post model has a One-to-many stack to the Promo component. Fetching the data is as simple as with any other model field. ### Union Type In this example we have a Page model with a Stack that holds the model `Navigation` and the components `Hero`, `Promo` and `Grid`. The example below shows how to fetch the different types. ### Fetching a single stack field You can choose between using a [multiple or single stack field](/content-modeling/field-types#stack-field), depending on the number of content items or components you intend to add to the model or component. When querying a single field, you'll receive a response similar to this: ```json copy { "data": { "Page": { "title" : "Home page", "hero": { "__typename": "Hero", "title": "All About Us ...", } } } } ``` ## Content reference The Content reference field stores a relation between one or more models. This powerful type allows you for example to create relationships between Posts and a Category or Posts and Author models. Prepr supports two types of Content references, One-to-many and Union Type references. One-to-many references allow you to create relationships between two types of defined models. The Union Type fields can reference to a set of models in a single field. ### One-to-many Our Post model has a One-to-many content reference to the Category model. Fetching the data is as simple as with any other model field. ### Union Type In this example we have a Page model with a Union type content reference to the `Hero`, `Promo` and `Grid` models. The example below shows how to fetch the different types. ### Fetching a single content reference field You can choose between using a [multiple or single content reference field](/content-modeling/field-types#content-reference-field), depending on the number of referenced content items you intend to add to the model or component. When querying a single field, you'll receive a response similar to this: ```json copy { "data": { "Post": { "title" : "Introducing Targeted Content personalization", "category": { "name": "Deep Dive" } } } } ``` ## Components Components are transformed into their own GraphQL types. Components are often used to represent a set of reusable fields. To query the content of a component you need to specify the subfields like you do with a content model. For example, we added a Component named `header` to the Page model. ## Remote content The *Remote content* field allows an editor to reference content from an eCommerce platform, external CMS or legacy system in Prepr content items. A Remote Source has its own fields which are configured in the schema. For example our `ecommerce` source has a `product_id`, `category_id` and `image_url` field. All Remote content items will come with a `_id` and `_json` field by default. Check out the how to [set up remote content](/content-modeling/creating-a-custom-remote-source) to start with your first integration. ### Fetching a single remote content field You can choose between using a [multiple or single remote content field](/content-modeling/field-types#content-reference-field), depending on the number of referenced items you intend to add to the model or component. When querying a single field, you'll receive a response similar to this: ```json copy { "data": { "Product": { "ecommerce": { "_id": "daa86b97-beec-488c-876d-aa48fb16720e", "product_id": "V234792749-23487298347", "category_id": "CEJKHDFKHGKFJH-33", "image_url": "https://image.ecommerce.com/fyd7tJBz01bgUEsbs7d02US01K8Tp00SB3Wn01WPneVKeCmQIM.jpg" } } } } ``` #### Remote content before API version `2023-01-10` (deprecated) In the API versions before `2023-01-10` Remote content fields are returned as generic `ContentIntegration` type. Let's see the same example in the deprecated versions. ## Form The *Form* field allows an editor to include forms from external sources in their content, such as from HubSpot, Typeform or Pipedrive. Take a look at the example form request and response with their corresponding fields. Check out the [HubSpot](/integrations/hubspot#make-hubspot-forms-available-in-content-items) and [Typeform](/integrations/typeform#add-form-field-to-schema) integration docs on how to set these up to include forms in the schema. ## Date The Date field adheres to ISO 8601 standard. For example, March 14, 2020 is represented as `2020-03-14`. ## Date & Time The DateTime field adheres to ISO 8601 standard. For example, 09.30 AM on March 14, 2020 is represented as `2020-03-14T09:30:00+00:00`. ## Date & Time Ranges The DateTime Range fields are following the specification of the Date / Date & Time fields and have two subfields, `from` and `until`. ## Location ## BusinessHours Represents the time periods that this location is open for business. Holds a collection of BusinessHoursPeriod instances. `regular_hours` Operating hours for the business.\ `special_hours` This typically includes holiday hours, and other times outside of regular operating hours. These should override regular business hours, ## Color The Color field is made up of HEX code. ## Tag Tags in Prepr have a predefined schema. This means that the type for any tag in the GraphQL schema follows the definition below. Source: https://docs.prepr.io/graphql-api/schema-field-types --- # Fetching single items When you want to fetch an individual content item of a given type you can use the single item query type. As explained in the [schema generation docs](/graphql-api/api-schema), the name of the fields is the *Singular name* of the content model from which they derive. In the following example, we use a content model called *Post*, with a *Singular name* of *Post*. ```graphql copy query { Post( id: "535c1e5a-4d52-4794-9136-71e28f2ce4c1" ) { _id, title } } ``` You can make your query more specific by including arguments. A full list of available arguments can be found below. ## Arguments The following arguments are available or required when querying a single content item: | argument | type | required | description | | ------------- |-------------| -------------|----------------------------------------------------------------------| | `id` | String | false | The ID of the content item you want to fetch | | `slug` | String | false | The slug of the content item you want to fetch | | `locale` | String | false | Locale for the content item. If not set, the default locale is used. | | `environment_id` | String | false | The environment ID is required if an organization token is used. It is used to fetch the content item from a specific environment.| ## Querying by ID Since IDs are unique in Prepr, you can find the content item you want using the id argument. Here's an example that shows how to query a Post type content item with the id "535c1e-...". ```graphql copy query { Post( id: "535c1e-4d52-4794-9136-71e28f2ce4c1" ) { _id, title } } ``` ## Querying by Slug Since slugs are unique within a content model, you can find a content item you want using the `slug` argument. Here's an example that shows how to query a Page type content item with the slug "about-us". ```graphql copy query { Page( slug: "about-us" ) { _id, _slug title } } ``` ## Querying single-item models Some models only have a single content item. It's possible to query these items without providing an ID because only one item is returned. Here's an example that shows how to query such an item. For more details on single-item models, check out the [Single-item model](/content-modeling/managing-models#single-item-model) docs. Source: https://docs.prepr.io/graphql-api/fetching-single-items --- # Fetching multiple items When you want to fetch multiple content items of a given type you can use the *Plural name* of the content model for the query type, for example `Posts`. Check out the [schema generation docs](/graphql-api/api-schema) for more details. In the following example, we use a content model called *Post*, with a *Plural name* of *Posts*. ```graphql copy query { Posts( limit : 30 ) { items { _id _slug title } } } ``` You can limit the number of content items returned by using the `limit` parameter. If you don't set this parameter, then 10 content items will be returned by default. To make your query more specific, consider including arguments from the following list. ## Arguments The following arguments are available or required when querying multiple items: | argument | type | required | description | | ------------- |-------------| -------------| -------------| | `locale` | String | false | Locale of a content item. If no locale is set, the default locale will be used. | | `locales` | \[String] | false | Optional fallback locales. | | `sort` | SortInputType | false | Read more in [Sorting](/graphql-api/fetching-sorting-collections). | | `where` | WhereInputType | false | Read more in [Filtering](/graphql-api/fetching-filtering-collections). | ## Preview vs Production Prepr provides default access tokens, *Preview* and *Production*, each with the necessary permissions to serve your staging and production sites, respectively. [Learn more about GraphQL permissions](/graphql-api/authorization#permissions). Source: https://docs.prepr.io/graphql-api/fetching-collections --- # Fetching multiple model items When you want to retrieve content items from multiple models, you can use the `ContentItems` query. Include the `__typename` argument to see which model the returned content items belong to. You can make your query more specific by including the necessary arguments for each model. Please see the example below. ```graphql copy query { ContentItems( limit : 30 ) { items { __typename ... on Post { _id, _slug } } } } ``` ## Query only content items from specific models To narrow query results to specific models, you can include a filter on its name by using the `_typename_any` argument. The following query retrieves all content items from the *Post* and *Page* models: ```graphql copy query { ContentItems( where : { _typename_any : [ "Post", "Page" ] } ) { items { ... on Post { _id, _slug } ... on Page { _id, _slug } } } } ``` Additionally, you can also use multiple filters to retrieve only specific content items from a model. Check out the [Filtering options reference](/graphql-api/fetching-filtering-collections) for more details. ## Arguments The following arguments are available or required when querying multiple items: | argument | type | required | description | |-------------------------|-----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `locale` | String | false | Locale of a content item. If no locale is set, the default locale will be used. | | `locales` | \[String!] | false | Optional fallback locales. | | `sort` | SortInputType | false | Read more in the [Sorting options reference](/graphql-api/fetching-multi-type-collection#sorting-multi-type-collections). | | `where` | WhereInputType | false | Read more in the [Filtering options reference](/graphql-api/fetching-multi-type-collection#filtering-multi-type-collections). | | `_typename_any` | \[String] | false | Allows filtering content items based on the given types. | | `people_also_viewed_id` | String | false | Allows recommending multi-type content based on the given IDs. Read more in [Fetching People Also Viewed content](/graphql-api/personalization-recommedations-people-also-viewed-content). | ## Filtering multi-model items To filter multi-model items, include the `where` argument in your query, followed by the relevant filter types for the fields on your model. Check out the full list of the available filters below. | filter | documentation |\ |----------------|-----------------------------------------------------------------------------------------------------------------------------| | `ID` | [Read more](/graphql-api/fetching-filtering-collections#id) | | `Search` | [Read more](/graphql-api/fetching-filtering-collections#full-text-search) | | `Slug` | [Read more](/graphql-api/fetching-filtering-collections#slug) | | `Tags` | [Read more](/graphql-api/fetching-filtering-collections#tags) | | `Content Type` | [Read more](/graphql-api/fetching-multi-type-collection#query-content-items-that-match-a-list-of-given-type-names) | ## Query by customer relation You can track customer engagement with your content items using [Prepr tracking](/data-collection/setting-up-the-tracking-code). If customers are allowed to bookmark, subscribe or like content items, this filter allows you to fetch the content items based on the customer event, such as `liked`. [Read more about Customer Relation filtering](/graphql-api/fetching-filtering-collections#customer-content-relation). ## Sorting multi-model items When fetching multiple content items at once, you can define the order of returned records by using the `sort` argument. This can be particularly useful when working with large datasets or complex queries. It helps to quickly locate specific records in your project. You can order results in ascending or descending order by specific system fields. More information can be found below. ### Sorting by common attributes It's possible to sort by the common attributes `created`, `changed` and `published` dates in ascending or descending order. The current values for sorting those fields are `created_on_ASC`, `created_on_DESC`, `changed_on_ASC`, `changed_on_DESC`, `publish_on_ASC`, `publish_on_DESC`. ```graphql copy type Query { ContentItems( sort : publish_on_DESC ) { items { _id, title } } } ``` ### Sorting by popularity This option will sort the content items on descending order by the number of views. ```graphql copy type Query { ContentItems( sort : popular ) { items { _id, title } } } ``` ### Default ordering If you don't pass an explicit order value the returned content items are ordered by `publish_on_DESC`. This means that the most recently published content item appear at the top of the list. Source: https://docs.prepr.io/graphql-api/fetching-multi-type-collection --- # Filtering when fetching multiple items Prepr automatically generates filters for the field types you add to your content models. You can apply these filters when [fetching multiple content items](/graphql-api/fetching-collections). For that, include the `where` argument in your query, followed by the relevant filter types for the fields on your model. Check out the full list of the available filters below. ## ID Every content item in Prepr has it's own unique identifier `_id` that can be queried using the following filters: | argument | type | Behaviour | | ------------- |----------| -------------| | `_id_any` | \[String] | Query content items that match any of the giving ids | | `_id_nany` | \[String] | Query content items that match none of the giving id's | In this example we will query all the Posts that are listed in the `_id_any` argument. ```graphql copy query { Posts( where : { _id_any : [ "ff71321f-e2d6-4d4d-b62b-530d8fb92392", "ff71321f-e2d6-4d4d-b62b-530d8fb92392" ] } ) { items { _id, title } } } ``` ## Slug Prepr content items can be filtered by their slugs. For example to show a block like "More posts". You can query the Slug field by using the `_slug_any` or `_slug_nany` argument. | argument | type | Behaviour |\ | ------------ |----------|---------------------------------------------------------| | `_slug_any` | \[String] | Query content items that match any of the giving slugs | | `_slug_any` | \[] | Query content items that have a slug | | `_slug_any` | NULL | Query content items that don't have a slug | | `_slug_nany` | \[String] | Query content items that match none of the giving slugs | In this example we query all the Posts with the exception of the ones that are listed in the `_slug_nany` argument. ```graphql copy query { Posts( where : { _slug_nany : ["/posts/olympics-results-2022"] } ) { items { _id _slug } } } ``` ## Locales You can specify `locale` as an argument when fetching a single item or multiple items. If you don't specify a locale, the default locale of the environment is used. The locale argument cascades, meaning that all linked content items resolve with the locale as specified. ```graphql copy query { Posts( locale : "de-DE" ) { items { id, title } } } ``` Check the [Localization](/graphql-api/localization) page for more on this. ## String String (Text) fields in your model can be filtered by using following filters: | argument | type | Behaviour | |---------------------------|-------------|------------------------------------| | `field_name` | String | Equals | | `field_name_contains` | String | Included in part of the string | | `field_name_not_contains` | String | Not included in part of the string | | `field_name_starts_with` | String | Starts with string | | `field_name_ends_with` | String | Ends with string | | `field_name_any` | \[String] | Matches is any of the giving strings equals the value | For example let's filter all authors where the `name` field starts with `Mik`. ```graphql copy query { Authors( where : { name_starts_with : "Mik" } ) { items { _id } } } ``` ## Full-text search You can use the `_search` argument to search for content items that contain a given text query. You can include this argument to query content items for a specific model or across multiple models. Check out the [fetching multiple model items reference](/graphql-api/fetching-multi-type-collection) for more info. In the examples below, we query content items that mention "amsterdam" somewhere in a `string` field. **Note** The full text search is not case-sensitive. **Search options** In combination with the `_search` argument, you can add the `_search_options` argument. The `SearchOptionInput` contains two boolean fields `includeReferences` and `includeNumeric` to extend the search to all numeric content fields or referenced content items. ```graphql copy query { Posts( where : { _search : "amsterdam", _search_options : { includeReferences : true, includeNumeric : true } }) { items { _id } } } ``` ## Integer Integer fields in your model can be filtered by using following filters: | argument | type | Behaviour | |------------------|----------|---------------------------| | `field_name` | Integer | Equals | | `field_name_gt` | Integer | Greater than | | `field_name_lt` | Integer | Less than | | `field_name_gte` | Integer | Greater than or equal to | | `field_name_lte` | Integer | Less than or equal to | For example let's filter all products where the `rating` field is `4` or higher. ```graphql copy query { Products( where : { rating_gt : 4 } ) { items { _id } } } ``` ## Float Float fields in your model can be filtered by using following filters: | argument | type | Behaviour | |------------------|--------|--------------------------| | `field_name` | Float | Equals | | `field_name_gt` | Float | Greater than | | `field_name_lt` | Float | Less than | | `field_name_gte` | Float | Greater than or equal to | | `field_name_lte` | Float | Less than or equal to | For example let's filter all products where the `price` field is `2.5` or higher. ```graphql copy query { Products( where : { price_gt : 2.5 } ) { items { _id } } } ``` ## Boolean Boolean fields in your model can be filtered by using their field name. | argument | type | Behaviour | | ------------- |-------------| -------------| | field\_name | Boolean | Equals | For example let's filter all products where the `premium` field is `true`. ```graphql copy query { Products( where : { premium : true } ) { items { _id } } } ``` ## Assets Asset fields in your model can be filtered by using the following filters: | argument | type | Behaviour | |----------------------|-----------|--------------------------------------------------------------------------------------| | `field_name._id_any` | \[String!] | Query content items that have a reference to an asset matching any of the giving Ids | | `field_name` | `{}` | Where the specified key has at least one asset is referenced | For example let's filter all organizations that have a filled `image` field. ```graphql copy query { Organizations( where : { image : {} } ) { items { _id } } } ``` ## Simple Reference / Stack All Content Reference or Stack fields that reference one model, can be filtered using filters on the fields of the model you are referencing. | argument | type | Behaviour | |--------------------|-----------|----------------------------------------------------------| | `field_name.where` | WhereType | Where arguments for the referenced model | | `field_name.where` | `{}` | Where the specified key has at least one item referenced | | `field_name` | NULL | Where the specified field is empty | For example let's filter all Products where there is at least a Variant in the `size` `small`. ```graphql copy query { Products( where : { variants : { size : "small" } } ) { items { _id } } } ``` ## Union Reference / Stack All union Content Reference or Stack fields (reference fields that allow for multiple types) can be filtered using some specific filters. | argument | type | Behaviour | |----------------------------|-----------|-------------------------------------------------------------------------------------| | `field_name._id_any` | \[String!] | Query content items that have a reference matching any of the giving ids | | `field_name._id_nany` | \[String!] | Query content items that have a reference matching none of the giving id's | | `field_name._slug_any` | \[String!] | Query content items that have a reference matching any of the giving slugs | | `field_name._slug_nany` | \[String!] | Query content items that have a reference matching none of the giving slugs | | `field_name._typename_any` | \[String!] | Allows filtering content items that have a reference matching on of the given types | | `field_name._slug_nany` | NULL | Where the specified field contains no references | For Stack fields, the filters apply only to referenced content items. Since version 2024-12-05, the `_typename_any` filter also applies to referenced component types. An example let's filter all Product where the parent page is a category. ```graphql copy query { Products( where : { parent : { _typename_any : ["Category"] } } ) { items { _id } } } ``` ## Date Date fields in your model can be filtered by using following filters: | argument | type | Behaviour | | ------------- |-------------| -------------| | `field_name` | String | Equals | | `field_name_gt` | String | Greater than | | `field_name_lt` | String | Less than | | `field_name_gte` | String | Greater than or equal to | | `field_name_lte` | String | Less than or equal to | For example let's filter all events on 1 September 2022. Dates in Prepr are saved in UTC Strings (ISO 8601). ```graphql copy query { Events( where : { date : "2022-09-01" } ) { items { _id } } } ``` ## Date Range Date range fields in your model can be filtered by using following filters: | argument | type | Behaviour | |-------------------------|-------------| -------------| | `field_name{from_gt}` | String | Greater than | | `field_name{from_gte}` | String | Greater than or equal to | | `field_name{from_lt}` | String | Less than | | `field_name{from_lte}` | String | Less than or equal to | | `field_name{until_gt}` | String | Greater than | | `field_name{until_gte}` | String | Greater than or equal to | | `field_name{until_lt}` | String | Less than | | `field_name{until_lte}` | String | Less than or equal to | For example let's filter all events after 28th August 2022. Dates in Prepr are saved in UTC Strings (ISO 8601). ```graphql copy query { Events( where : { "event_dates": { "from_gte": "2022-08-28" } } ) { items { _id } } } ``` ## DateTime DateTime fields in your model and the system fields `_publish_on`, `_created_on` and `_changed_on` can be filtered by using following filters: | argument | type | Behaviour | | ------------- |-------------| -------------| | `field_name` | String | Equals | | `field_name_gt` | String | Greater than | | `field_name_lt` | String | Less than | | `field_name_gte` | String | Greater than or equal to | | `field_name_lte` | String | Less than or equal to | For example let's filter all events after 1 October 2022. Dates in Prepr are saved in UTC Strings (ISO 8601). ```graphql copy query { Events( where : { date_gt : "2022-10-01T08:00:00+00:00" } ) { items { _id } } } ``` ## DateTime Range DateTime range fields in your model can be filtered by using following filters: | argument | type | Behaviour | |-------------------------|-------------| -------------| | `field_name{from_gt}` | String | Greater than | | `field_name{from_gte}` | String | Greater than or equal to | | `field_name{from_lt}` | String | Less than | | `field_name{from_lte}` | String | Less than or equal to | | `field_name{until_gt}` | String | Greater than | | `field_name{until_gte}` | String | Greater than or equal to | | `field_name{until_lt}` | String | Less than | | `field_name{until_lte}` | String | Less than or equal to | For example let's filter all events after 28th August 2022. Dates in Prepr are saved in UTC Strings (ISO 8601). ```graphql copy query { Events( where : { "event_dates": { "from_gte": "2022-08-20T00:00:00+00:00" } } ) { items { _id } } } ``` ## Remote Content Remote content fields in your model can be filtered by the ID used in the Remote Source. | argument | type | Behaviour | |-----------------------|----------|-----------------------------------------------------| | `field_name{_id_any}` | \[String] | Matches items referencing one of the specified ID's | For example let's filter all Category pages where our product is mentioned. ```graphql copy query { ProductCategories( where : { products : { _id_any : [ "2387hasdkury3287h376s-23483268" ] } }) { items { _id title } } } ``` ## Business hours Business hours fields in your model can be filtered by using following filters: | argument | type | Behaviour | |----------------------------|--------------|--------------------------------| | `field_name{open_day_in}` | \[DayOfWeek!] | Open on one of the given days | | `field_name{open_on_in}` | \[\_Date!] | Open on one of the given dates | For example let's filter all locations open on Monday. ```graphql copy query { Locations( where : { "business_hours": { "open_day_in": [ MONDAY, FRIDAY ] } } ) { items { _id } } } query { Locations( where : { "business_hours": { "open_on_in": ["2025-02-10"] } } ) { items { _id } } } ``` ## List List fields in your model can be filtered by using following filters: | argument | type | Behaviour | | ------------- |-------------| -------------| | `field_name` | String | Equals | | `field_name_contains` | String | Included in part of the string | | `field_name_any` | \[String] | Equals one of the given strings | | `field_name_starts_with` | String | Starts with string | | `field_name_ends_with` | String | Ends with string | For example let's filter all Products where the `color` field is `red` or `blue`. ```graphql copy query { Products( where : { color_any : ["red", "blue"] } ) { items { _id } } } ``` ## Location Location fields in your model can be filtered by using following filters: | argument | type | Behaviour | | ------------- |-------------| -------------| | `field_name_within_circle` | Object | Object with a list of the following arguments | | `field_name_within_circle.lat` | Float | - | | `field_name_within_circle.lon` | Float | - | | `field_name_within_circle.radius` | Int | Distance in kilometers | For example let's filter all Events within 10 kilometers of `Amsterdam`. ```graphql copy query { Events( where : { location_within_circle : { lat : 40.730610, lon : -73.935242, radius: 10 } }) { items { _id location { latitude longitude } } } } ``` ## Tags Tag fields in your model can be filtered by using following filters: | argument | type | Behaviour | | ------------- |-------------| -------------| | `field_name_any` | \[String] | Equals any of the given tags (or) | | `field_name_all` | \[String] | Equals all of the given tags (and) | | `field_name_nany` | \[String] | Equals none of the given tags | | `field_name_has` | Boolean | Includes at least one tag | The example below filters all Nobel prize winning authors with the `prize` tag and a value of `Nobel`. ```graphql copy query { Authors( where : { prize_any : "Nobel" } ) { items { _id } } } ``` You can also filter by the slug of a tag instead of the actual value. The example below filters all Nobel prize winning authors with the `prize` tag and a slug of `nobel`. ```graphql copy query { Authors( where : { prize_any : ["slug:nobel"] } ) { items { _id } } } ``` **Deprecated Tag Filters** You can query tag fields using the `_tags_any`, `_tags_all`, `_tags_has`, `_tags_nany` arguments. These filters work on all tags referenced in a content item, not restricted by a field name. | argument | type | Behaviour | | ------------- |----------| -------------| | `_tags_any` | \[String] | Equals any of the given tags (or) | | `_tags_all` | \[String] | Equals all of the given tags (and) | | `_tags_nany` | \[String] | Includes at least one tag | | `_tags_has` | Boolean | Equals none of the given tags | ## Customer content relation You can track customer engagement with your content items using the [Prepr Tracking Code](/data-collection/setting-up-the-tracking-code). If customers are allowed to bookmark, subscribe or like content items, this filter allows you to fetch content items based on the customer event, such as `Liked`. You can use this filter option when [fetching multi-model items](/graphql-api/fetching-multi-type-collection). For example, we query all posts items bookmarked by the specified customer. ```graphql copy query { ContentItems( where: { _typename_any : ["Post"] _customer_relation : { id : "ad5714b0-dea5-46b3-9386-0f109ebbe29b", event : Bookmark } } ) { items { ... on Post { name } } } } ``` Next to the Prepr Customer ID, querying using the customer's Reference ID is also possible. ```graphql copy query { ContentItems( where: { _typename_any : ["Post"] _customer_relation : { reference_id : "ad5714b0-dea5-46b3-9386-0f109ebbe29b", event : Bookmark } } ) { items { ... on Post { name } } } } ``` New Event types created in the tracking API will be available are a few hours. ## Environment ID filter If you are using the GraphQL API with a multi-environment token you can filter content items on the environment they are created in. | argument | type | Behaviour |\ |-----------------------|----------|-----------| | `_environment_id_any` | \[String] | Qeury content items from environments with the specified IDs | In this example we query all Posts that are created in any of the environments listed in the `__environment_id_any` argument. ```graphql copy query { Posts( where : { _environment_id_any : [ "ff71321f-e2d6-4d4d-b62b-530d8fb92392", "ff71321f-e2d6-4d4d-b62b-530d8fb92392" ] } ) { items { _id, _environment_id title } } } ``` ## Combining filters It's also possible to combine different filters. This example shows how to do that. ```graphql copy query { Products( where : { variants : { size : "small" } premium: true, rating_gt: 4 } ) { items { _id } } } ``` ## Conditional filters Conditional filters allow you to filter results based on sets of criteria. In this example, we filter all items that have a boolean field set to true or have a high rating: ```graphql copy query { Products( where : { _or : [ { boost: true }, { rating_gt: 4.5 } ] } ) { items { _id } } } ``` Source: https://docs.prepr.io/graphql-api/fetching-filtering-collections --- # Sorting when fetching multiple items When [fetching multiple content items](/graphql-api/fetching-collections), you can define the order of returned records by using the `sort` argument. This can be particularly useful when working with large datasets or complex queries. It helps to quickly locate specific records in your project. You can order results in ascending or descending order by specific system fields and some non-relational custom fields that you add to your model. More information can be found below. ## Sorting by common attributes It's possible to sort by the common attributes `created`, `changed` and `published` dates in ascending or descending order. The current values for sorting those fields are `created_on_ASC`, `created_on_DESC`, `changed_on_ASC`, `changed_on_DESC`, `publish_on_ASC`, `publish_on_DESC`. ```graphql copy query { Posts( sort : publish_on_DESC, locale : "en-US") { items { _id, title } } } ``` ## Sorting by fields You can sort content items by the content of all `Text`, `Float`, `Integer` and `Date` `DateTime` fields in either ascending or descending order. For example we've added an integer field `order` to the model. That creates two new sort options: `order_ASC` and `order_DESC`. ```graphql copy query { Posts( sort : order_ASC, locale : "en-US") { items { _id, title } } } ``` ## Default ordering If you don't pass an explicit order value the returned content items are ordered by `publish_on_DESC`. This means that the most recently published content item appear at the top of the list. Source: https://docs.prepr.io/graphql-api/fetching-sorting-collections --- # Paginating when fetching multiple items Pagination allows you to display a large number of records in a more manageable way. To enable pagination, you need to define two parameters in your query: `Limit` and `Skip`. By defining these parameters, you can break down a large dataset into smaller parts that can be displayed on separate pages. Please find more details below. ```graphql copy query { Posts ( limit : 15, skip: 0 ) { items { _id, title }, total } } ``` In the above example, a client retrieves content items by repeating the same request, changing the `skip` query parameter as follows: `Page 1: skip=0, limit=15` `Page 2: skip=15, limit=15` `Page 3: skip=30, limit=15` `etc.` ## Limit The `Limit` parameter sets a maximum number of results to return per query. It breaks down the entire results into portions. By default, API returns 10 items per call. ## Skip The `Skip` parameter sets an offset, i.e., how many items to omit before returning the results. ## Returned data When fetching multiple items, the response includes the meta-data field `total` and the requested items in the items field. The total field contains the total number of content items in that collection. Please note, adding the total field requires processing costs, and in large datasets this can slow down the query significantly. Source: https://docs.prepr.io/graphql-api/fetching-paginating-collections --- # Localizing content Prepr offers the Localization API that enables you to publish content in multiple locales. You can [add locales to your project](/content-management/localizing-content#adding-a-locale) by navigating to the environment settings. When fetching [multiple items](/graphql-api/fetching-collections) and [a single item](/graphql-api/fetching-single-items), you can specify a `locale` as an argument in your query. If no locale is specified, the *default locale* is used. Please note, the `locales` argument cascades, meaning that all linked content items will resolve with the specified locale. [Check out our localization docs](/content-management/localizing-content) for more details. ## Available locales Retrieve the locales available in your environment, making it easy to implement localization switches in your front end. The `_DefaultLocale` will return the environment's default locale. ```graphql copy query { _Locales _DefaultLocale } ``` ## Fallback locales When fetching multiple items, `locales` argument can be given to set fallback locale(s). The argument is processed from left to right. In this example, if there is no version for the `de-DE` locale, the `en-US` locale will be returned. ```graphql copy query { Pages ( locales : ["de-DE", "en-US"] ) { items { _id, title } } } ``` ## Fetching all locales All content items are generated with a `_localizations` field that contains all available locales for that content item. Make sure to add the same fields to the top level of the query, since the `_localizations` field will only return the values of items that are also specified outside the `_localizations` field. ```graphql copy query { Pages { items { _id, _slug title _localizations { _id _slug title } } } } ``` ## Fetching locale by HTTP header You can add the `Prepr-Locale` header to your request to override the default locale. ```html copy 'Prepr-Locale' : 'en-US' ``` Source: https://docs.prepr.io/graphql-api/localization --- # Previewing content Accessing unpublished content can be useful for previewing how a new content item will look before making it available to everybody. The GraphQL API gives you control over whether you want to access published or unpublished content items. To view content items that are not yet published, use the *Preview* access token created by Prepr during the initial environment setup. ![preview access token](https://assets-site.prepr.io/6vcmqkzrxusz//preview-access-token.png) With this access token, you can retrieve content items in all available statuses, including *To do*, *In progress*, *Review*, *Done*, and *Published*, and make any necessary changes before publishing them. ![example query response with unicode characters](https://assets-site.prepr.io/23a2ny9qei6r//stega-encoding-example.png) Alternatively, you can create a new access token yourself and define token permissions according to your specific needs. [Read more about GraphQL permissions](/graphql-api/authorization#permissions). Source: https://docs.prepr.io/graphql-api/fetching-previewing-content --- # Fetching A/B tests with Prepr GraphQL {/* A/B testing */} # Fetching an A/B test A/B test your content, check out the [A/B testing guide](/ab-testing/setting-up-ab-testing) for a quick introduction. ## How to fetch a variant An A/B test variant is set up for any item or component in a *Stack*. Prepr automatically links an A or B variant to a particular customer when they visit the web app. To show one of the variants, simply pass the *Prepr-Customer-Id* in the header of the GraphQL API request. If you set up your content item, for example, a *Page* with *Stack* elements and you activate an A/B test on a specific element in the stack, for example, the *Page header*, the query will return the appropriate version for that customer. Use the [*\_context* system field ](/graphql-api/schema-system-fields#_context) to set up reporting variables in your front-end. ## Pre-fetching the variant A/B test your content by pre-fetching both variants for static site rendering. If you enabled A/B testing on your content model, pass the `personalize: false` argument in the API request. Use the [\_context system field](/graphql-api/schema-system-fields#_context) to choose the variant that you want to show in your front-end. Source: https://docs.prepr.io/graphql-api/personalization-recommedations-ab-testing --- # Fetching personalized content with Prepr GraphQL API {/* PERSONALIZATION */} # Fetching personalized content Prepr lets you generate fully customized experiences to boost engagement and conversion rates in a web app. [Check out the Personalization guide](/personalization/setting-up-personalization) for more details. A native personalization engine is built into the [Stack field](/content-modeling/field-types#stack-field). Once added to a model, the Stack field may include multiple content items and components and allows editors to personalize these elements with *Adaptive content*. With *Adaptive content*, content editors can make different versions of content for various visitor segments. You can then show the right content to each visitor based on their segment giving them a personalized experience. ## Segmentation You can link adaptive content variants to one of more segments in Prepr. - When customers are maintained in Prepr, you can [create segments with conditions](/personalization/managing-segments) directly in Prepr to target them with adaptive content based on their behavior on the web app. The front end can then [fetch the adaptive content by customer](#fetch-content-by-customer) in this case. - If you source segments from another application, for example, by using an external CRM/CDP system, then you need to create a matching [customer segment](/personalization/managing-segments#use-external-segments-from-crmcdp-systems) in Prepr to reference the external customer segment. This customer segment can then be used to determine the adaptive content for these visitors. The front end can then [fetch adaptive content by variant](#fetch-content-by-variant) or [fetch it by customer segment](#fetch-content-by-customer-segment) in this case. ## How to fetch adaptive content Fetch adaptive content by a variant, a customer or a customer segment. ### Fetch content by customer If customers are maintained in Prepr, you can retrieve adaptive content using an API request that includes an HTTP header called `Prepr-Customer-Id` containing a *Customer ID* or *Customer Reference ID* of the web app visitor. This allows Prepr to match a web app visitor to a segment in your Prepr environment and return the matching content for this visitor based on the personalized content in the *Stack* field. Note, the visitor ID in the HTTP header must correspond to the ID used when [sending events to Prepr](/data-collection). If the `Prepr-Customer-Id` header is not sent or contains no data, the API will return the variants set up on the *Stack* field and marked for *All other users*, in other words, that are not matched to any segment. See an example query below: If the API request includes an HTTP header `Prepr-Customer-Id` containing a Customer ID, then you’ll get adaptive content shown on the **RESPONSE** tab. Otherwise, general content will be returned like in the **ALL OTHER USERS** tab. ### Fetch content by variant A variant is the adaptive content linked to one or more customer segments. You can retrieve adaptive content for a specific personalized variant by passing the segments as arguments in your query. For example, use a segment that is from an external CDP/CRM system. See an example query below: ### Fetch content by customer segment If customers are created and maintained in another CRM or CDP system, you can pass the segments as a comma-separated string using the HTTP Header `Prepr-Segments`. Include the relevant Prepr *Customer Segment ID* or *ID* in your API request. See an example query below: If the API request includes an HTTP header `Prepr-Segments` containing the segment IDs, then you’ll get adaptive content shown on the **RESPONSE** tab. Otherwise, general content will be returned as the **ALL OTHER USERS** tab shows. ## How to pre-fetch adaptive content for static (SSG) websites Prepr lets you pre-fetch all data for all segments so you can implement personalization for static (SSG) websites. For that, pass the `personalize: false` argument in the API request. Use the [\_context system field](/graphql-api/schema-system-fields#_context) to choose the variant that you want to show in your front-end. See an example query below: {/* ## How to start with Customer ID's In most cases, your application would already have the notion of a Customer ID. This ID actually represents a specific device or browser used by someone whose identity you often do not know at all. Often a Session ID is used that is limited in time and will invalidate after a set period of inactivity. Make sure to consistently use the same IDs across all touch points. This will ensure the customer always gets the same experience. If you currently do not have a Customer of Session ID, here are a few design options: **Session ID** Create a Session ID stored in a HttpOnly cookie. **Customer ID** Offer a SignIn to your app option with an SSO provider of your choice, or use [Prepr Customers](/mutation-api/customers#query-by-id). */} Source: https://docs.prepr.io/graphql-api/personalization-recommendations-personalized-stack --- # Fetching similar content with Prepr GraphQL API {/* recommendations */} # Fetching similar content Display content similar to a given item based on common content attributes and content. Check out the [Recommendations guide](/recommendations) for a quick introduction. The GraphQL API creates a corresponding GraphQL Type with a *"similarity"* algorithm for each content model in your environment. The plural Type name of the content model is prefixed with `Similar_`. For example Post generates a Type `Similar_Posts`. Pagination options (except limit) and the `total` items field are disabled when using this query. ```graphql copy query { Similar_Posts( id : "b3f76d7d-732b-4fd6-a9e9-a967dba3d09b" ) { items { _id, title } } } ``` ## Filtering recommended content items To narrow down the recommended content items, use the same filters that are available when [filtering collections](/graphql-api/fetching-filtering-collections). In the following example, we query all Posts where `premium` is set to true. ```graphql copy query { Similar_Posts( id : "b3f76d7d-732b-4fd6-a9e9-a967dba3d09b", where : { premium : true } ) { items { _id } } } ``` Source: https://docs.prepr.io/graphql-api/personalization-recommedations-similar-content --- # Fetching 'People Also Viewed' recommendations {/* recommendations */} # Fetching People Also Viewed content Display content similar to a given item based on visitors' behavior. Check out the [Recommendations guide](/recommendations) for a quick introduction. The GraphQL API creates a corresponding GraphQL Type with a "people also viewed" algorithm for each content model in your environment. The plural Type name of the content model is prefixed with `PeopleAlsoViewed_`. For example Post generates a Type `PeopleAlsoViewed_Posts`. ```graphql copy query { PeopleAlsoViewed_Posts( id : "90276002-d628-4ba6-b3c8-f756c486b67b" ) { items { _id, title } } } ``` ## Filtering recommended content items To narrow down the recommended content items, use the same filters that are available when [filtering collections](/graphql-api/fetching-filtering-collections). In the following example, we query all Posts where `premium` is set to true. ```graphql copy query { PeopleAlsoViewed_Posts( id : "90276002-d628-4ba6-b3c8-f756c486b67b", where : { premium : true } ) { items { _id } } } ``` Source: https://docs.prepr.io/graphql-api/personalization-recommedations-people-also-viewed-content --- # Fetching popular content with Prepr GraphQL API {/* recommendations */} # Fetching popular content Display your trending content items. Check out the [Recommendations guide](/recommendations) for a quick introduction. The GraphQL API creates a corresponding GraphQL Type with a *"Popularity"* algorithm for each content model in your environment. The plural Type name of the content model is prefixed with *Popular\_*. For example Post generates a Type `Popular_Posts`. ```graphql copy query { Popular_Posts { items { _id, title } } } ``` Check the [Capture Documentation](/data-collection) on how to get started with events. ## Filtering recommended content items To narrow down the recommended content items, use the same filters that are available when [filtering collections](/graphql-api/fetching-filtering-collections). In the following example, we query all Posts where `premium` is set to true. ```graphql copy query { Popular_Posts( where : { premium : true } ) { items { _id } } } ``` Source: https://docs.prepr.io/graphql-api/personalization-recommedations-popular-content --- # Dynamic content field *The Dynamic Content field* allows content editors to combine various elements such as headings, texts, videos, social media posts, maps, assets, remote content, and components to create rich content. This page lists sample requests you can use to query different types of content available in the Dynamic Content field. ## Dynamic content components ### Heading (text) Heading elements contain two fields. `body` contains the content of the heading, `format` tells you if the heading is H1, H2, H3 ect. formatted. ### Paragraph (text) Paragraph elements contain two fields. `body` contains the content of the paragraph, `format` tells you if the heading is HTML or plain formatted. ### Links (text) You can identify links with the `` HTML tag in the `body` and `html` string values like in the example response below. ### Assets You can get the `url` of the asset and in the case of videos, the `playback_id`. Check out the [Asset Field](/graphql-api/schema-field-types#assets) section for all asset fields. ### Components Components are transformed into their own GraphQL types. Components are often used to represent a set of reusable fields. To query the content from a component you need to specify the subfields, like you do for any other type. In our example the `dynamic_content_field` contains a component named `HeaderComponent`. ### Social posts Social posts can be one of the following types: InstagramPost, YouTubePost, FacebookPost, TwitterPost, SpotifyPlaylist, TikTokPost, VimeoPost, SoundCloudPost, ThreadsPost and BlueskyPost. The returned urls are [oEmbed](https://oembed.com/) supported urls. ### Quote ### Menu item (NavigationItem) ### Location (Coordinates) ### Remote content The *Remote content* field allows an editor to reference content from an eCommerce platform, external CMS or legacy system in Prepr content items. A Remote Source has its own fields which are configured in the schema. For example our `ecommerce` source has a `product_id`, `category_id` and `image_url` field. If you add a Remote source to the Dynamic Content Editor a specific Remote Source Collection is generated #### Remote content before API version `2023-01-10` (deprecated) In the API versions before `2023-01-10` Remote content fields are returned as generic `ContentIntegrations` and `ContentIntegration` type. Let's see the same example in the deprecated versions. Source: https://docs.prepr.io/graphql-api/schema-field-types-dynamic-content-field --- # API basics *Check out this article to learn the basics of REST API.* ## The API URL You can reach the REST API through two URLs. The first option is through our CDN, the second option is directly on the API. Requests through the CDN are cached and are therefore always lightning fast. We recommend this URL for all front-end applications that retrieve and display content items: `https://cdn.prepr.io/` If you want to create, update or delete content items via the API we recommend the direct URL: `https://api.eu1.prepr.io/` ## The HTTP method In general, the *Hypertext Transfer Protocol (HTTP)* is the underlying format that is used to structure requests and responses for effective communication between an application and a server. To call the REST API, you will need to use the appropriate *HTTP method* with the `application/json` content type. ## Errors and validation The REST API will validate and execute all inputs and return a response in JSON format. When a request contains a mistake, the API might return an error message in the response. Read more about possible [statuses and errors](/mutation-api/statuses-errors). ## Read after write consistency When you get a successful response for a mutation request, changes are persisted in Prepr. It is important to note that some changes are not visible immediately after the update. If you fetch content with a GraphQL API request right after a mutation with the REST API, you might get back stale content. Because, when you create, delete or update content the request is distributed around the globe with a short delay. Check out the [caching doc](/graphql-api/caching) for more details. Source: https://docs.prepr.io/mutation-api/api-basics --- # Authorization *From this article, you’ll learn how to get access to the Prepr REST API.* To access the Prepr API you first need to authenticate your app with an OAuth bearer token. A token provides scoped access to a single environment, you need to obtain another token for every new environment you want to access. Organizations with an Enterprise plan can create access tokens on the organization level. We recommend using different access tokens for different applications or front end applications, for example, one for an iOS app and another for Android app. This allows you to revoke them individually in the future and manage access independently. **Sign in to your Prepr account** Go to [https://signin.prepr.io](https://signin.prepr.io) and sign in with your Prepr account credentials. Then navigate to the Environment you want to use. **Create an Access token**\ Go to **Settings → Access tokens** and click the **Add access token** button. ![Mutation access token example](https://assets-site.prepr.io/4xs5ez419qts//mutation-access-token-example.png) Enter a **Name** and select the **Rest API scopes** to give the new token API access. In most cases just adding `content_items` is sufficient. If you want to update content items, add the `content_items_publish` scope and make sure to set the **Bound to user** name to the user who's responsible for this mutation project. Click save and copy the generated access token to use later. To authenticate the request include an `Authorization` HTTP header with the value of the access token you copied. ```http copy curl -v https://cdn.prepr.io/{{endpoint}} -H 'Authorization: Bearer sdfg...' ``` Or ```http copy curl -v https://api.eu1.prepr.io/{{endpoint}} -H 'Authorization: Bearer sdfg...' ``` If you fail to include a valid access token, the endpoint will return a status code 401. Source: https://docs.prepr.io/mutation-api/authorization --- # Statuses and errors *This article describes the standard HTTP status and error codes the REST API returns.* ## HTTP response status codes The REST API uses standard HTTP status codes to indicate whether a request is successful or not. In general, status codes within the *2xx range* indicate a successful request. When you receive an HTTP status code different from *2xx*, then you probably have one of the following issues: | Status code | Description | |-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | **200 OK** | The request is successful. However, the API response might contain an error. For example, if your query is too complex or contains typos, etc. | | **401 Unauthorized** | The access token is invalid or a scope is missing. | | **400 Bad Request** | The request did not pass validation, please check the response for more information. For example, the `access_token_not_bound_to_user` error means the **Bound to user** value is empty on the [mutation API access token](/mutation-api/content-items-create-update-and-destroy) you created.| | **404 Not Found** | The requested resource or endpoint could not be found. | | **405 Method Not Allowed** | The requested HTTP method is not supported for the specified resource. | | **429 Too Many Requests** | The access token sent too many requests in a given timeframe, check the HTTP headers to debug. | | **5xx Internal Error or Service Unavailable** | Something went wrong on the Prepr servers. Try your request again after a few seconds. | ## Rate limits **There are no rate limits enforced on requests that hit our CDN cache, i.e. the request doesn't count toward your rate limit, and you can make an unlimited amount of cache hits.** API Rate limits specify the number of requests an app can make to Prepr APIs in a specific time frame. Every request counts against a per minute and a per hour rate limit. By default, the Prepr API enforces rate limits of 35 req/sec, 800 req/minute, and up to 10K req/hour. Higher rate limits may apply depending on your current plan. When an access token or IP gets rate limited, the API responds with the `429 Too Many Requests` HTTP status code. Use the HTTP headers in order to understand where the application is at for a given rate limit, on the method that was just utilized. | header attribute | description | | ------------- |-------------| | X-Prepr-RateLimit-Limit | the rate limit ceiling for a one minute window | X-Prepr-RateLimit-Remaining | the number of requests left for a one minute window | X-Prepr-Retry-After | the remaining seconds before the rate limit resets | X-Prepr-RateLimit-Reset | the remaining window before the rate limit resets, in UTC epoch seconds Source: https://docs.prepr.io/mutation-api/statuses-errors --- # Upgrade guide *Learn more about our version support policy and the steps you need to take to upgrade your app to a newer API version.* ## Support policy Prepr guarantees technical assistance and security updates for each new version of the REST API for at least 32 months. Please note that **we do not change your API version automatically to avoid breaking your code**. Once you are ready to upgrade, please follow the instructions below. ## How to upgrade to a newer API version Your API version controls the API behavior you see (for example, how your schema is generated and what fields you can request). When a major or breaking change is introduced to the API, Prepr releases a new version based on the release date. In this case, we encourage our customers to upgrade their API versions as soon as possible. To upgrade to a newer API version, you need to generate a new access token for your Prepr environment as follows: 1. Go to **Settings → Access tokens** and click **Add access token**. 2. On the **New access token details** page, provide the name of the token. 3. Next, define permissions for this access token under **REST Permissions**. Permissions allow you to choose which content item statuses are accessible for an access token. 4. Click **Save** to confirm the settings. ![Create a new access token](https://assets-site.prepr.io//49luhgfwri38-add-rest-api-scopes.png) Once you've created a new access token, you'll notice the new API version indicated on the **Access tokens overview** page. By default, the new access token uses the latest API version on the token generation date. ## Released REST API versions You can check out the previous releases below. | version | release date | end-of-life on | |------------|--------------|------------------| | 2023-11-02 | 2023-11-06 | t.b.a | | all before | - | t.b.a | ### Version `2023-11-02` This version adds Draft Mode support and performance updates. #### What's new - A new Content Item parameter `last_published_on` has been added. This field returns the timestamp of the last time a new version was published. - The label for all Content Items has been updated from `Publication` to `ContentItem`. #### Enabling Draft Mode The following changes are active if you switch on Draft Mode. **publishing**\ The `publish_on` field is only required when you acutely want to publish or schedule the current version of the item. If the `workflow_stage` is set to Done, and you add a `publish_on` date/time the item will be published on that specified date/time. When updating an existing content item, changing the `workflow_stage` to something else than Done will no longer unpublish the item. To unpublish an existing content item, use the new unpublish endpoint. ``` PUT: /content_items/{id}/{locale}/unpublish ``` **status/workflow**\ The `status` field for a content item is renamed to `workflow_stage`. The response and request params are simplified: ``` // Draft Mode Off: "status": { "nl-NL": { "id": "cff13c2a-615a-4f85-a50d-cc05104e6d6b", "created_on": "2018-12-24T09:09:25+00:00", "changed_on": null, "label": "Status", "body": "In progress" } } // Draft Mode On: "workflow_stage": { "nl-NL": "In progress" } ``` Please take in mind that if you request that `status` in your `?fields` param, you need to update this to `workflow_stage` too. **webhook events**\ Everytime a new version is published the `content_item.published` event is sent to your webhook endpoint. With drafts off this event is only triggered once (on first publish). Source: https://docs.prepr.io/mutation-api/upgrade-guide --- # Fetching single items Use the Prepr REST API to fetch a single content item when you need to get specific content for a bulk process. For example, to get content from linked content items as part of a project to migrate content from a legacy system to Prepr CMS. Before calling a REST API endpoint to fetch a single content item, go to **Settings → Access tokens** to create an access token with the *REST API scope* `content_items`. To fetch a content item, send a `GET` request to the `https://cdn.prepr.io/content_items` endpoint. There are two ways to fetch a single content item. ## Query by Id Since Ids are unique in Prepr, you will be able to find the content item you want using the `id` argument. Here is an example that shows how to query a content item with the ID "535c1e-...". ```http copy GET: /content_items/535c1e-4d52-4794-9136-71e28f2ce4c1 ``` ## Query by Slug Since slugs are unique within a content model, you will be able to find a content item you want using the `slug` argument. Here is an example that shows how to query a Page type content item with the slug "nieuws/...". Source: https://docs.prepr.io/mutation-api/fetching-single-items --- # Fetching multiple items Use the Prepr REST API to fetch a collection of content items when you need to get content for a bulk process. For example, to get content from linked content items as part of a project to migrate content from a legacy system to Prepr CMS. Before calling a REST API endpoint to fetch a collection of content items, go to **Settings → Access tokens** to create an access token with the *REST API scope* `content_items`. To fetch content items, send a `GET` request to the `https://cdn.prepr.io/content_items` endpoint. Filter content items by the criteria listed below. ## Search Prepr content items can be searched on their title or text fields. ### Title search Filter content items by searching in the title field with fuzzy search. ```http copy GET: /content_items?title[0][fz]=hello world ``` ### Full text search Filter content items by searching in all text fields. ```http copy GET: /content_items?q[0][fz]=hello world ``` ## Workflow stage Prepr content items can be filtered on their workflow stage. You can query the workflow stage field by using the workflow stage as an argument. ## Locales Prepr content items can be filtered on their locale. You can query the locale field by using the locales as an argument. ## Model With Prepr you can have multiple models, like Article, Hero, Banner, Menu, Blog etc. All those different pieces can be defined as a Model. ## Dates Prepr content items can be filtered on a different type of dates. You can query the dates fields by using `publish_on`,`created_on`, `changed_on`, `expire_on` as an argument. The examples below all use `publish_on`. **Note:** all timestamps are UTC. ## Tags Content items collections can be filtered on their tags. You can query the tag fields by using the `tags` argument. ## Content Fields Prepr content items collections can be filtered on a specific content model field value. It's possible to apply advanced filters for the following field types: `Boolean`, `ContentIntegration`, `Coordinates`, `DateTimeRange`, `Integer`, `Publication`, `Text`. The filter options per type are different. It's also possible to combine multiple filters. ### Boolean Get content items with boolean false: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "eq": 0 } ] } } } ``` Get content items with boolean true: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "eq": 1 } ] } } } ``` ### Remote Content Get content items that does contain any content integration item: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "has": true } ] } } } ``` Get content items that doesn't contain any remote source item: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "has": false } ] } } } ``` ### DateTimeRange Get content items that within or outside the given timestamp(s): **Note**: You can only use this filter if field type is `Daterange`, not `Date and time`! Options: It's possible to combine the options below. | argument | description | | ------------- |-------------| | `lt` | Less than from date. | | `lte` | Less than or equals from date. | | `gt` | Greater than from date. | | `gte` | Greater than or equals from date. | Greater than the from date ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "gt": 1600000000 } ] } } } ``` Less than the from date ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "lt": 1600000000 } ] } } } ``` In between than the from date ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "gt": 1600000000, "lt": 1700000000 } ] } } } ``` ### Integer Get content items with an integer with exact given value: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "eq": 10 } ] } } } ``` ### Content reference or Stack fields Get content items that contains the given content item. For example, if a customer is viewing content item `10c503b4-e86b-422d-89d3-502b3faee34e`, you may want to display suggestions that are related to this publication. This is not a recommendation, but linked to each other by you/editor. This filter will result in linked content items. ### Type Text Get content items with a text field with exact given value: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "eq": "Hello world!" } ] } } } ``` Get content items with a text field with match/search given value: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "fz": "world" } ] } } } ``` ### Type List Get content items with a list field with exact given value: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "eq": "Hello world!" } ] } } } ``` Get content items with a list field with match/search given value: ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "{{field id}}": [ { "fz": "world" } ] } } } ``` ### Combining multiple filters It is possible to filter on multiple fields at the same time. In this example we are going to filter on **boolean** (id: `premium`) and **integer** (id: `category_id`). ```json copy { "model": { "id": "edc503b4-e86b-422d-89d3-502b3faee34e" }, "items": { "{{locale}}": { "premium": [ { "eq": 1 } ], "category_id": [ { "eq": 10 } ] } } } ``` This will result in content items that are marked as premium and have an integer/category with value 10. Source: https://docs.prepr.io/mutation-api/fetching-filtering-collections --- # Working with fields Use the `fields` argument in any REST API content items endpoint to choose the content fields that you want to see in the response. ## Combine fields You can combine different fields in the `fields` argument of the request to choose all the content that you want to see in the response such as `items`, `title`, `model`, `locales`, `workflow_stage`, `environment`, `created_by`, `updated_by`, and `assigned_to`. See the example request and response below when combining some fields. ## Nested fields Some fields have sub-fields, for example the `assigned_to` returns a person object. A person object has multiple sub-fields, but for this example we only want to see the sub-field `emails`. You can find all sub-fields [here](#field-types). You can achieve this by nesting those fields in the argument of the request with `{` and `}` like in the example below. ## Content fields To request the main content include the field `items` in the `fields` argument. To see sub-fields of items, specify the `api_id` of the sub-field in the argument. Go to **Schema → Model → Field type settings** to get the `api_id` of the fields that you want to include. For example, a content item has a cover image field (type Assets) with api\_id `cover`. In this example, you can access the sub-field `cdn_files` of your asset field in one request like in the example below. ## Field types The list of field types returned in the `items` object of a content item depends on the related model. In the example responses below, you can see that the `api_id` of each field is returned in `items`. Here is a list of field types to give you a better understanding of what to expect in the response of a `GET` request. ### Text The Text field can be a single line, multiple lines, or HTML like in the example response below. ```json copy { "items": { "en-US": { // The content item entry for this locale. "title": { // API Id of a single line text field "id": "gmQh3QLgu80l1QLMg9qUj6nwr97YxqkbPhhUf7rO", "created_on": "2023-01-01T09:56:21+00:00", "changed_on": null, "label": "Text", "body": "Headline", "format": null }, "my_text_area": { // API Id of a text area field with multiple lines "id": "gmQh3QLgu80l1QLMg9qUj6nwr97YxqkbPhhUf7rO", "created_on": "2023-01-01T09:56:21+00:00", "changed_on": null, "label": "Text", "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", "format": null }, "my_html_text": { // API Id of an HTML text field "id": "gmQh3QLgu80l1QLMg9qUj6nwr97YxqkbPhhUf7rO", "created_on": "2023-01-01T09:56:21+00:00", "changed_on": null, "label": "Text", "body": "

Heading 1

Heading 2 

Some bold text and italic

  • First bullet
  • Second bullet
  1. Step 1

A useful link


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": "
  • first bullet point
  • second bullet point
", "format": null }, { // Embedded ordered list in the dynamic content field "id": "f7e27135-f5b8-46e8-b103-f1f7807f7a6e", "created_on": "2023-09-27T15:05:25+00:00", "changed_on": null, "label": "Text", "body": "
  1. step 1
  2. step 2
", "format": null }, { // Embedded table in the dynamic content field "id": "6c8bc9fa-256c-499c-8636-3452cb02176a", "created_on": "2023-09-27T15:05:25+00:00", "changed_on": null, "label": "Text", "body": "
ProsCons
TastyLots of calories
Easy to makeNeed to use the oven
", "format": null }, { // An embedded asset field "label": "Asset", "items": [ { "id": "6059ecee-270f-46b0-b286-2e3e9374d33a", "created_on": "2023-09-20T11:55:11+00:00", "changed_on": "2023-09-20T13:12:27+00:00", "label": "Photo", "name": "blueprint", "body": null, "author": null, "status": null, "replaceable": true, "reference_id": null, "width": 1141, "height": 1280, "extension": "jpg", "original_name": "blueprint", "mime_type": "image/jpeg" } ] }, { // An embedded location field "id": "6059ecee-270f-46b0-b286-2e3e9374d33a", "created_on": "2023-09-20T11:55:11+00:00", "changed_on": "2023-09-20T13:12:27+00:00", "label": "Coordinates", "latitude": "52.3736018", "longitude": "4.9002881" } ], "label": "ElementBox" } } } } ``` ### Assets Assets are images, videos, and audio files or documents that are linked to a content item. ```json copy { "items": { "en-US": { // The content item entry for this locale. "cover": { // API Id of the Asset field "items": [ { "id": "bac0aa60-dfa3-4f4e-9261-35a4fc693a76", "created_on": "2022-11-23T12:50:33+00:00", "changed_on": "2022-11-23T12:50:33+00:00", "label": "Photo", "name": "bg-cta-1", "body": null, "author": null, "status": null, "replaceable": true, "reference_id": null, "width": 1919, "height": 939, "extension": "png", "original_name": "bg-cta-1", "mime_type": "image/png" } ], "label": "Asset" } } } } ``` ### Integer Integers are whole numbers, and are often used to store stock quantities, prices in cents, etc. like in the example below. ```json copy { "items": { "en-US": { // The content item entry for this locale. "quantity": { // API Id of the Integer field "id": "e356b423-71bc-40b5-8b6b-0611108658be", "created_on": "2023-03-14T16:34:16+00:00", "changed_on": null, "label": "Integer", "value": 122 } } } } ``` ### Float Float types are number entries with decimal places, for accurate calculation such as the price of an item, distance, or weight. ```json copy { "items": { "en-US": { // The content item entry for this locale. "price": { // API Id of the Float field "id": "69f6f04b-719e-49fd-b80c-b0037f495a31", "created_on": "2023-03-14T16:34:16+00:00", "changed_on": null, "label": "Float", "value": 122.12 } } } } ``` ### Boolean The Boolean field has one of two possible values: true or false. ```json copy { "items": { "en-US": { // The content item entry for this locale. "needs_social_post": { // API Id of the Float field "id": "4d32c2f1-69cd-4280-abe1-f5e548584417", "created_on": "2023-03-09T09:45:23+00:00", "changed_on": null, "label": "Boolean", "value": true } } } } ``` ### Stack The Stack field contains a list of (personalized) models/components. This is a powerful type that allows you to create a site using the Stack field as your page builder. ```json copy { "items": { "en-US": { // The content item entry for this locale. "stack": { // The API Id of a stack field "items": [ // Contains all components and items in the stack { // A link to an existing Call to action content item "id": "4c0622c1-f635-4a0a-83de-8f56bc5b9ea4", "created_on": "2023-03-17T10:07:30+00:00", "changed_on": "2023-03-17T10:07:30+00:00", "label": "Publication", "read_time": { "en-GB": 1 }, "publish_on": { "en-GB": "2023-03-17T10:07:00+00:00" } }, { // Embedded component "items": { "description": { "id": "006e3c8e-ea6b-44bd-886d-abcdf5357b6a", "created_on": "2023-03-17T10:11:43+00:00", "changed_on": null, "label": "Text", "body": "As far back as I can remember, I've always eaten french toast. It was usually a quick Sunday morning breakfast instead of pancakes or the go-to snack to use up the last stale bread slices. This is one of the easiest recipes that you can find for a quick treat.", "format": null }, "social_media_image": { "items": [ { "id": "54bbbdda-470b-4048-9a9e-0b3bca205003", "created_on": "2023-03-09T14:16:39+00:00", "changed_on": "2023-03-09T14:16:47+00:00", "label": "Photo", "name": "French toast", "body": null, "author": null, "status": null, "replaceable": true, "reference_id": null, "width": 3024, "height": 4032, "extension": "jpg", "original_name": "4tq8iogbqhfi-pexels-sean-stevens-4623075", "mime_type": "image/jpeg" } ], "label": "Asset" }, "title": { "id": "9a087714-324c-41cb-96c6-212f410cdf74", "created_on": "2023-03-17T10:11:43+00:00", "changed_on": null, "label": "Text", "body": "Excuse my french toast", "format": null } }, "id": "1f3dec32-96e1-410a-bda8-22a634f9fd26", "label": "PublicationElement" // Label for component } ] } } } } ``` ### Content Reference The Content reference field contains a link between one or more models like in the example below. ```json copy { "items": { // The content item entry for this locale. "en-US": { // API Id of a content reference field "authors": { "items": [ { // Id of the existing content item "id": "a69bebd0-b438-41ab-8fc8-86353afaf57e", "created_on": "2023-01-27T10:35:52+00:00", "changed_on": "2023-01-30T08:43:51+00:00", "label": "Publication", "read_time": { "en-GB": 1 }, "publish_on": { "en-GB": "2023-01-27T10:35:00+00:00" } } ], // Label for a content reference "label": "Publication" } } } } ``` ### 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. ```json copy { "items": { // The content item entry for this locale. "en-US": { // The API Id of the embedded component "seo": { "items": { // API Id of a text field in the component "description": { "id": "6eefa140-c2f4-499e-a236-794936eeb057", "created_on": "2023-09-25T09:31:37+00:00", "changed_on": null, "label": "Text", "body": "test", "format": null }, // API Id of the asset field in the component "social_media_image": { "items": [ { "id": "6059ecee-270f-46b0-b286-2e3e9374d33a", "created_on": "2023-09-20T11:55:11+00:00", "changed_on": "2023-09-20T13:12:27+00:00", "label": "Photo", "name": "blueprint", "body": null, "author": null, "status": null, "replaceable": true, "reference_id": null, "width": 1141, "height": 1280, "extension": "jpg", "original_name": "blueprint", "mime_type": "image/jpeg" } ], "label": "Asset" }, // API Id of a text field in the component "title": { "id": "baffc883-5104-4cc9-8813-c8920a943867", "created_on": "2023-09-25T09:31:37+00:00", "changed_on": null, "label": "Text", "body": "Test SEO title", "format": null } }, // Component Id and label of the embedded component "id": "85461317-fd8e-40f8-b453-dbf6ef9c68dd", "label": "PublicationElement" } } } } ``` ### Remote content The Remote content field references content in an external CMS, legacy system of eCommerce platform. [Check out the Content Integration setup guide](/content-modeling/creating-a-custom-remote-source) for more details. ```json copy { "items": { // The content item entry for this locale. "en-US": { // The API Id of the remote content field "products": { "items": [ { "id": "1", "body": "Pizza slicer", "description": "This handy tool has more uses than you may realize. It can be used to slice your pizza and shape dough for the perfect pies.", "image_url": "https://prepr-example-show-content-demo-patterns.stream.prepr.io/w_1920,h_1080/4frprlq6w4k6-pizza-slicer.png", "data": { "sku_id": 1, "price": 1299, "stock": 5 }, "content_integration": { "id": "62cc3bec-6978-4ba6-a699-d379ff0a93de" } } ], "label": "ContentIntegrationItem" } } } } ``` ### Date & Time The Date and time field adheres to the ISO 8601 standard. This field content differs in the response depending on the following field settings: - **The Type** - This type can be either *Date*, *Date range* or *Business hours* which you can identify from the `label` like in the example below. - **Time selection** - When time selection is enabled the format is `Y-m-d H:i:s` instead of `Y-m-d`. - **Multiple dates** - When *Allow extra dates* is enabled, the field will be an `items` object like in the example below. ```json copy { "items": { "en-US": { // The content item entry for this locale. "event_date": { // The API Id of a date field without time "id": "73fd5c62-78b4-434a-966b-4aba04f3648a", "created_on": "2023-01-01T16:25:53+00:00", "changed_on": null, "label": "DateTime", "value": "2023-01-01", "format": "Y-m-d" }, "start_date_and_time": { // The API Id of a date field with time "id": "c1c5c7cf-d737-4fd9-9949-940b84cbf454", "created_on": "2023-01-01T16:28:21+00:00", "changed_on": null, "label": "DateTime", "value": "2023-01-01 18:25:00", "format": "Y-m-d H:i:s" }, "project_duration": { // The API Id of a date field with ranges "id": "abb46555-013f-4e2e-871e-344b243332f6", "created_on": "2023-01-01T16:25:53+00:00", "changed_on": null, "label": "DateTimeRange", "from": "2023-01-01", "until": "2024-12-31", "format": "Y-m-d" }, "event_duration": { // The API Id of a date field with ranges including time "id": "efd799d9-ee9d-4ec1-8cc3-487b1ecb347a", "created_on": "2023-01-01T16:25:53+00:00", "changed_on": null, "label": "DateTimeRange", "from": "2023-01-01 00:00:00", "until": "2024-12-31 23:59:59", "format": "Y-m-d H:i:s" }, "seasons": { // The API Id of a date field with multiple date ranges "items": [ { "id": "2d701a86-7867-479a-bf09-36dbd847a36f", "created_on": "2023-01-01T16:28:21+00:00", "changed_on": null, "label": "DateTimeRange", "from": "2023-12-01", "until": "2024-02-29", "format": "Y-m-d" }, { "id": "72df271a-ebda-4372-b1ab-9d5ca36ef585", "created_on": "2023-06-01T16:28:21+00:00", "changed_on": null, "label": "DateTimeRange", "from": "2023-09-01", "until": "2023-11-30", "format": "Y-m-d" }, ... ], "label": "DateTimeRange" }, "opening_times" : { // The API Id of a date field with Business hours type "items": [ { "id": "50425271-b86c-4d0a-886e-988642808d77", "created_on": "2023-03-13T10:59:21+00:00", "changed_on": null, "label": "BusinessHours", "state": "open", "open_day": 1, //Days are defined as 1 through 7, starting on Monday. So Monday would be 1, Tuesday would be 2, and so on. "open_time": "00:00", "close_day": 2, "close_time": "00:00", "valid_from": null, "valid_until": null }, { "id": "c9509f72-e277-49e1-bbc5-2a31df543cae", "created_on": "2023-03-13T10:59:21+00:00", "changed_on": null, "label": "BusinessHours", "state": "open", "open_day": 2, "open_time": "04:30", "close_day": 3, "close_time": "01:30", "valid_from": null, "valid_until": null }, { "id": "9b602eb5-e376-4965-9837-d604350d0724", "created_on": "2023-03-13T10:59:21+00:00", "changed_on": null, "label": "BusinessHours", "state": "open", "open_day": 2, "open_time": "01:30", "close_day": 2, "close_time": "02:00", "valid_from": null, "valid_until": null }, { // Example of an exception to the regular business hours: Closed on Xmas day "id": "37ff000f-a875-44a9-a91e-751700b1e599", "created_on": "2023-03-13T14:59:21+00:00", "changed_on": null, "label": "BusinessHours", "state": "closed", "open_day": 4, "open_time": "00:00", "close_day": 4, "close_time": "00:00", "valid_from": "2025-12-25", "valid_until": "2025-12-26" } ], "label": "BusinessHours" } } } } ``` ### Location The Location field contains Google Maps coordinates of a specific location in the content item. ```json copy { "items": { "en-US": { // The content item entry for this locale. "office_location": { // API Id of the location field "id": "18e6f038-7766-4c65-8ef0-89e1c6a32926", "created_on": "2023-01-01T16:05:08+00:00", "changed_on": null, "label": "Coordinates", "latitude": 21.3137, "longitude": -157.806 } } } } ``` ### Social The Social field contains embedded social posts in the content item. The `label` depends on the social platform and will be one of these values: `TwitterPost`, `InstagramPost`, `YouTubePost`, `FacebookPost`, `VimeoPost`, `SoundCloudPost`, `SpotifyPlaylist`, `TikTokPost`, `ApplePodcast`. ```json copy { "items": { "en-US": { "weekly_social_post": { // The Api Id of a social field in the content item "id": "fe556b3f-20a1-416d-a6c7-baa7ccf29ead", "created_on": "2023-01-01T10:04:57+00:00", "changed_on": null, "label": "TwitterPost", "url": "https://twitter.com/SpaceX/status/1633941127081652224?s=20" } } } } ``` ### Color The Color field includes a HEX code. ```json copy { "items": { "en-US": { "border_color": { // The Api Id of a color field in the content item "id": "3035280e-c171-42cd-a643-c1fee2083543", "created_on": "2023-03-13T11:49:58+00:00", "changed_on": null, "label": "Color", "body": "#c73434", "format": "Color" } } } } ``` ### Tag The Tag field includes tags like keywords for your content item. ```json copy // The Tag field returns a list of tag items: { "items": { "en-US": { "search_keywords": { // The API Id of a Tags field in the content item "items": [ // An items array with a list of tags { "id": "7ca6249b-7b63-4f96-a090-c92b5c297a11", "created_on": "2023-03-09T09:45:23+00:00", "changed_on": null, "label": "Tag", "body": "awesome", "slug": "awesome" }, { "id": "7ca6249b-7b63-4f96-a090-c92b5c297a11", "created_on": "2023-03-09T09:45:23+00:00", "changed_on": null, "label": "Tag", "body": "great", "slug": "great" }, { "id": "7ca6249b-7b63-4f96-a090-c92b5c297a11", "created_on": "2023-03-09T09:45:23+00:00", "changed_on": null, "label": "Tag", "body": "awesome and great", "slug": "awesome and great" }, ], "label": "Tag" } } } } ``` Source: https://docs.prepr.io/mutation-api/fetching-working-with-fields --- # Paginating Prepr returns collections of resources, such as content items, 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 25 resources by repeating the same request, changing the `skip` query parameter to `25`. 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 100. The API will throw a Bad Request for values higher than 100 and values other than an integer. The default number of resources returned by the API is 25. ## 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/fetching-paginating-collections --- # 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 content items created, changed, published dates in either ascending or descending order. The current values for sorting those fields are `created_on`, `-created_on`, `changed_on`, `-changed_on`, `publish_on`, `-publish_on`, `title`, `-title`. ## Default ordering If you don't pass an explicit order value the returned content items will be ordered descending by content item published timestamp `-publish_on`. This means that the most recently published content item will appear at the top of the list. Source: https://docs.prepr.io/mutation-api/fetching-sorting-collections --- # Create & update content items Use the Prepr REST API to do mutation on content items in bulk. For example, to create or update content items as part of a project to migrate content from a legacy system to Prepr CMS. Before calling a REST API endpoint to create or update content items, go to **Settings → Access tokens** to create an access token with *REST API scopes* `content_items` and `content_items_publish`. Set the **Bound to user** name to the user who's responsible for this mutation project. ![Mutation access token example](https://assets-site.prepr.io/4xs5ez419qts//mutation-access-token-example.png) 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. ## Create a content item To create a content item, send a `POST` request to the `https://api.eu1.prepr.io/content_items` endpoint. Make sure the `Content-Type` in the header is set to `application/json` to send a valid JSON body. When the content item is created successfully, an auto-generated Id of the new content item will be returned in the response. The metadata fields below need to be included in the body of the request. |Field name| Description | Required (POST) | Required (PUT)| |----------|----------------|--------------|---------------| |`model`|The related model of the content item that you want to create. Go to the **Schema** tab and click the button at the top of the model and choose **Copy model ID**. Use this value to set the `id` field in the `model` object.| ✓|✗| |`locales`| An array of the locales that are created in this request in ISO code (i18n) format, for example, `en-US` or `de-DE`. |✓|✓| |`workflow_stage`| The content item workflow stage object with locales in it. Check out more details in the [workflow doc](/content-management/collaboration). To publish this content item immediately or on a `publish_on` date in the future, set the `workflow_stage` value to `Done`. This is required for a POST when drafts is enabled. If not, set `status` instead. |✓|✗| |`status`| The content item status object with locales in it. If you have drafts enabled, this field is not required in a POST request and set the `workflow_stage` instead. |✓|✗| |`slug`| Set a value for the slug of the content item. If you set a value that already exists, the API will generate a unique value. Check out [the slug field doc](/content-modeling/field-types#slug-field) for more details.|✗|✗| |`publish_on`|This is the date when this content item needs to be published. To publish a content item immediately, set this value to the current date or a past date UNIX Timestamp.|✗|✗| |`expire_on` | Set this date if you want a published content item to be archived.|✓|✗| |`items`| The actual content fields are listed in this object and the field types in this list depend on the `model`. A `locale` in ISO code (i18n) format, for example, `en-US` or `de-DE` is the key for each content item entry like in the examples below.|✗|✗| In the examples below, you can see requests based on the *Article* and *Person* models from the [*Blog* pattern](/content-modeling/examples/blog). You can also see the schema in a Prepr environment with Demo data or create a model and choose the *Blog* template. ### Person example ```json copy { "model": { "id": "fd24889b-7dc8-4ed6-91ee-07b24609fdee" }, "publish_on": { "en-US": "1695286367" }, "locales": [ "en-US" ], "workflow_stage": { "en-US": "Done" }, /* If drafts is disabled, set "status" instead of "workflow_stage" as follows: "status": { "en-US": { "body": "Done" } }, */ "items": { // The key to create one content item entry for this locale. "en-US": { // The API id of a text field "bio": { "body": "This blogger is well-known all around the world." }, // The API id of a text field "full_name": { "body": "Renowned Blogger" }, // The API id of an assets field "profile_pic": { "items": [ { // Id of an existing asset in this environment "id": "cf91df18-df0e-4a20-b84a-8ef448becef9" } ] } } } } ``` ### Article example ```json copy { "model": { "id": "b2298bbf-eda1-4f5c-9648-9213ecef6746" // The Id of the Article model }, "locales": [ "en-US" ], "workflow_stage": { "en-US": "In progress" }, "items": { "en-US": { // Create one content item for this locale. "authors": { // The content reference to the Person content item "items": [ { "id": "54515b1a-b6d6-4002-956a-39d809023921" //This Id was in the response of the create request of the Person content item } ] }, // The API Id of the dynamic content field "content": { "items": [ { // Need a label for each element in the dynamic content field "label": "Text", "body": "Ingredients", "format": "H2" }, { // Embedded bullet points in the dynamic content field "label": "Text", "body": "
  • first bullet point
  • second bullet point
" }, { // Embedded ordered list in the dynamic content field "label": "Text", "body": "
  1. step 1
  2. step 2
" }, { // Embedded table in the dynamic content field "label": "Text", "body": "
ProsCons
TastyLots of calories
Easy to makeNeed to use the oven
" }, { // An embedded asset field "label": "Asset", "items": [ { "id": "6059ecee-270f-46b0-b286-2e3e9374d33a" // Id of an existing asset in this Prepr environment } ] }, { // An embedded location field "label": "Coordinates", "latitude": "52.3736018", "longitude": "4.9002881" }, { // Items object of a component "items": { "text": { "body": "Everyone has their own way to crack an egg." }, "title": { "body": "The best way to crack an egg" } }, // The component Id for the embedded component "id": "906ac62d-b59d-4346-ac7f-bf10a92fbb22" }, ] }, // The API Id of the asset field "cover": { "items": [ { // Id of an existing asset in this Prepr environment "id": "6059ecee-270f-46b0-b286-2e3e9374d33a" } ] }, // The API Id of an HTML Text field "excerpt": { "body": "

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://api.eu1.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://api.eu1.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" ], "items": { "en-US" : { "title" : { "body" : "A new Post title" } } } } ``` The `PATCH` request supports the following field types: `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": "

Heading 1

Heading 2 

Some bold text and italic

  • First bullet
  • Second bullet
  1. Step 1

A useful link


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, "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://api.eu1.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://api.eu1.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://api.eu1.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://api.eu1.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://api.eu1.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 Customer segmentation organizes customers 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://api.eu1.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://api.eu1.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, customers 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 `. Paste the HTML you created into the body field and click save. Copy the `Id` (on the left side of the page), you need this later. ## Request the Magic Link After a customer has clicked on the "Sign-In" link on your front-end, make a request to the Customer API to sent the Magic Link. ```json copy { "email" : "ryan.vaughan@example.prepr.io", "email_template" : { "id" : "a8d0cd02-c339-46fa-8602-6a5cbf991487" }, "redirect_url" : "https://example.com/sign_in" } ``` Replace the email template ID with the ID from the template you created in step 1. ```http copy POST https://customers.prepr.io/request_sign_in ``` If the request is successful the customer receives a magic link in their mailbox. ## Implementing Sign-In handler If the customer clicks on the sign-in link, the API will redirect the customer back to your site. The API will add a query param `access_token` to the url. ```http copy https://example.com/sign_in?access_token= ``` This token is a `temporary sign-in token`. To use this for following requests we need to convert it to an `Personal Access Token`. This is pretty simple, just create a POST request to `https://customers.prepr.io/sign_in_with_magic` with the received token as the Authentication Bearer header. This will result in a new Personal Access Token for the customer: ```json copy { "id": "a22287ff-7277-4583-8adb-0ca3e55e21b8", "last_seen": "2021-03-01T15:35:58+00:00", "first_name": "Ryan", "last_name": "Vaughan", "access_token": { "access_token": "Gniw9Mt90cLj7136M5ao0B7mGHHMHXXw68NlKMyuiinmVU426Dw", "token_type": "Bearer", "expires_in": null } } ``` **Done!** 🥳 You've completed the sign-in. Source: https://docs.prepr.io/mutation-api/sign-in-magic-link --- # Fetching a customer profile After a customer signs in, you can query the customer profile using the following endpoint. ```http copy GET: https://customers.prepr.io/customers/me ``` ## Customer object To expand the customer object when querying a customer profile, add the following field names to the fields parameter. ### Fields | field name | type | description | |------------------|--------|-----------------------------------------------------------------------| | `id` | String | - | | `first_name` | String | Lists the first name of the customer. | | `last_name` | String | Lists the last name of the customer. | | `date_of_birth` | String | Lists the date of birth of the customer. Format: `Y-m-d`. | | `email` | String | Email addresses of the customer. | | `phone` | String | Phone number of the customer. | | `reference_id ` | String | Lists the reference\_id of the customer. | | `tags ` | Array | Lists tags of the customer. | | `segments ` | Array | Lists the segment the customer is in. | ```http copy GET: https://customers.prepr.io/me?fields=custom,emails,tags ``` ```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": "31612345678", "tags": { "items": [ { "body": "Amsterdam" } ] } } ``` Source: https://docs.prepr.io/mutation-api/customers-fetching-customer-profile --- # Signing-out customers Sometimes you will find yourself needing to log your customer out. Here is a small example of how to do so. To invalidate the session make an `HTTP Delete` request to `https://customers.prepr.io/sign_out` with the Personal Access Token as the Authentication Bearer header. If the session is destroyed, the API will reply with a `204 No Content` status code. Source: https://docs.prepr.io/mutation-api/sign-out --- # Resending webhooks In some cases you may need to re-trigger multiple webhook requests for your front end or an integration. This can be accomplished by triggering the following endpoint. ```http copy GET /content_items/bulk/webhooks ``` ## Parameters All filtering parameters from the content items collection endpoint can be added to this request. | argument | type | required | description | default | |--------------|:-------|------------|------------------------------------------------------------------------------------------------------------------------------|----------| | `event` | String | true | Defines the webhook event. Possible values are: `content_item.created` `content_item.changed` `content_item.published` `content_item.unpublished` `content_item.deleted` | | | `webhook_id` | Object | false | Defines which webhooks should be triggered. | | | `skip` | Int | false | You can specify an offset with the skip query parameter. | 0 | | `limit` | Int | false | You can specify the maximum number of items as a limit query parameter. The highest limit you can set is 1000. | 25 | ### Resending one webhook The example below resends webhook events for all the content items with the tag `1fb70a05-7cab-4f7e-bae7-bbf7f69fd091` or `f9b73994-76bf-49a0-87f8-505252e21086` to a webhook with the ID `312cae95-9343-43e8-bf4a-93898261acd7`. ```json copy { "event" : "content_item.published", "webhook_id" : [ { "eq": "312cae95-9343-43e8-bf4a-93898261acd7" } ], "limit" : 1000, "skip": 0, "tags" : [ { "in" : [ "1fb70a05-7cab-4f7e-bae7-bbf7f69fd091", "f9b73994-76bf-49a0-87f8-505252e21086" ] } ] } ``` ### Resending multiple webhooks The example below resends webhook events for all the content items with one of the specified tags to two webhook endpoints. ```json copy { "event" : "content_item.published", "webhook_id" : [ { "in": [ "312cae95-9343-43e8-bf4a-93898261acd7", "312cae95-9343-43e8-bf4a-93898261acd7", ] } ], "limit" : 1000, "skip": 0, "tags" : [ { "in" : [ "1fb70a05-7cab-4f7e-bae7-bbf7f69fd091", "f9b73994-76bf-49a0-87f8-505252e21086" ] } ] } ``` ## Response The API response includes arrays of IDs for queued content items and webhooks. Additionally, it provides a count for queued webhooks events labeled as `total_queued` and a count for the number of filtered content items labeled as `total_items`. This supports straightforward pagination of content items when necessary. Source: https://docs.prepr.io/mutation-api/bulk-webhooks --- # Adding the Tracking Code (manual method) To create a tracking code manually, please follow the steps below: 1. Copy the following code snippet: ```html copy ``` 2. Replace `PREPR_TRACKING_ID` with your actual access token taken from **Settings > Access tokens**. 3. Add the code to the **\** section of your website. Once you've set up the tracking pixel, proceed with [recording events](/data-collection/recording-events). Source: https://docs.prepr.io/developing-with-prepr/tracking-code-manual-method --- # 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). ![Multi-select](https://downloads-site.prepr.io/477b864d-5956-4d74-8b3e-5f53daf81ffd.gif) *** ## 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). ![Embed fields](https://assets-site.prepr.io/w_1920/s3-preprmarketing/e19e1968-4694-4a3b-b9ab-13b0c8df411b.png) *** ## 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. ![Dynamic content field](https://assets-site.prepr.io/w_1920/s3-preprmarketing/12fa42c4-babe-4ee6-a25b-907cc404dbda.png) *** ## 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 static](https://assets-site.prepr.io/w_1920/s3-preprmarketing/308e420a-ecab-4dfe-a409-a614d46e1c9f.png) *** ## 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). ![Content item slug](https://assets-site.prepr.io/w_1920/s3-preprmarketing/0e68d5d0-1627-4a98-851d-a07c8e892c9c.png) *** ## 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. ![Publications](https://assets-site.prepr.io/w_1920/s3-preprmarketing/70dd5971-b727-4960-a3a4-8ef5ff3ef08b.png) *** ## 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) ![Dynamic content editor](https://3f8neni5ytfp.b-cdn.net/1e80f251-b379-4d95-be5f-52c98a6577f2.gif) *** ## 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. ![Mentioning](https://assets-site.prepr.io/w_1920/s3-preprmarketing/b0b36cc3-963f-418a-818f-49ebdc6f4d43.png) 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. ![Get notified](https://assets-site.prepr.io/w_1920/s3-preprmarketing/d4fd02a9-48c7-48db-90ab-01a892798306.png) *** ## 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. ![Major Update](https://3f8neni5ytfp.b-cdn.net/1e80f251-b379-4d95-be5f-52c98a6577f2.gif) 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. ![Small and wide view](https://3f8neni5ytfp.b-cdn.net/b219b35a-0b26-4b37-874d-0142d443740e.gif) *** ## 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. ![Automize workflow](https://assets-site.prepr.io/w_1920/s3-preprmarketing/41c3aeb8-2348-4bea-99c8-e55d782af0ab.png) *** ## 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). ![Locale](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8b898728-d331-4a55-8b54-2adce7fb07d1.png) *** ## 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. ![Design update notifications](https://assets-site.prepr.io/w_1920/s3-preprmarketing/a1c85422-ab62-46f6-ac35-0f9b26dcb71c.png) *** ## 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). ![App list update](https://assets-site.prepr.io/w_1920/s3-preprmarketing/4428396e-8698-4441-80e7-c30f6b0e18eb.png) *** ## 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. ![Disabled buttons](https://assets-site.prepr.io/w_1920/s3-preprmarketing/80621b6f-dd4e-4f9e-95b8-5685c3cbe025.png) *** ## 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**'. ![Update model settings](https://downloads-site.prepr.io/a5a3fac7-fcb1-437b-8ca7-9dc1ea25205c.gif) *** ## 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. ![Row hover](https://assets-site.prepr.io/w_1920/s3-preprmarketing/f9e97a2e-a17c-4d39-9f7b-6670ec394d44.png) *** ## 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: ![Heading styling](https://assets-site.prepr.io/w_1920/s3-preprmarketing/24a1d04d-1b4c-46f2-892b-b988e9455913.png) *** ## 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). ![Password](https://assets-site.prepr.io/w_1920/s3-preprmarketing/bc267d62-f099-49b0-99d0-f80bf377ad53.png) *** ## 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). ![Search filters](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/ba5f671c-3b35-47f7-bb23-127991c09d6a.png) *** ## 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). ![New segmentation builder](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/9bbbe8a0-50c0-4894-a77c-558a578c240d.png) *** ## 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. ![Saved publication filters](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/48651daa-bec6-4d3a-af08-90e63f7c0ec5.png) *** ## 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). ![vi-VNssss](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9c8423b0-9024-41dd-a77c-ea65ab5b93be.png) *** ## 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. ![API ID](https://assets-site.prepr.io/w_1920/s3-preprmarketing/c191ad54-68c2-4f3f-8962-d4ac460cae03.png) *** ## 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). ![Agency user accounts](https://assets-site.prepr.io/w_1920/s3-preprmarketing/c83d1be3-3a25-4aa0-9875-0222ba7cb374.png) *** ## 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). ![Manage model names](https://assets-site.prepr.io/w_1920/s3-preprmarketing/e5f2d661-293d-4efc-95d2-077b7aeacd91.png) *** ## 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) ![Slug construct](https://downloads-site.prepr.io/7fd795cb-f728-4ebd-bedf-7e3887fe1bd0.gif) *** ## 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). ![Publication](https://assets-site.prepr.io/w_1920/s3-preprmarketing/21ee7410-ce93-458a-b950-4690b31539e9.png) *** ## 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). ![Lithuanian poles](https://assets-site.prepr.io/w_1920/s3-preprmarketing/2e9fce19-96c1-40b8-bbff-d184520aff89.png) *** ## 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. ![Create your publication](https://downloads-site.prepr.io/97b29a23-8c28-49fd-81c4-725240101ff8.gif) *** ## 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). ![Manage segments](https://assets-site.prepr.io/w_1920/s3-preprmarketing/6c0ac96e-f8da-4377-a196-582e322b77cc.png) *** ## 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. ![Empty customer lists](https://assets-site.prepr.io/w_1920/s3-preprmarketing/812e9218-1bd6-4585-b923-7284ba03b31e.png) *** ## 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. ![Generate links](https://downloads-site.prepr.io/0a7f83f5-8045-4231-b1e5-94e07f35439a.gif) *** ## 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. ![Selecting-a-typeform](https://assets-site.prepr.io/w_1920/s3-preprmarketing/73a37e1c-0bd2-47b2-a47c-6a87acfd5b37.png) 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. ![Auto-suggest](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/cefd323b-13b2-439a-a18f-17f7caa63391.png) - **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. ![Checkboxes](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/9ca067f3-cc41-4c53-a060-c3f2197c3d92.png) **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 English](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8f946ef2-5a37-445f-8934-e901450658e3.png) Caption in German publication ![Caption in German](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8cec0430-75a9-46ba-986d-4733835dbb66.png) *** ## 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. ![Align images](https://assets-site.prepr.io/w_1920/s3-preprmarketing/65a0b981-f703-4fd4-8f5d-7e0c46b61428.png) *** ## 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. ![Import elements](https://assets-site.prepr.io/w_1920/s3-preprmarketing/c9222aa3-8bfb-46c0-98e1-9ef096bc4699.png) 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. ![Sending tweets](https://assets-site.prepr.io/w_1920/s3-preprmarketing/6e30c779-570a-4a54-99a4-44714fae5ccc.png) **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! ![Prepr application](https://assets-site.prepr.io/w_1920/s3-preprmarketing/ff89e934-ae8e-4d23-8c60-69df6869aef0.png) *** ## 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. ![Export customers](https://assets-site.prepr.io/w_1920/s3-preprmarketing/c8b83879-865b-4474-96c7-716b6d81c3ab.png) **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). ![Slug construct](https://assets-site.prepr.io/w_1920/s3-preprmarketing/66741c02-6b5d-4bd2-b88c-a6fca6916416.png) *** ## 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/exif). ![Start using exif data](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8a56bce0-d1ca-4550-a461-c2a170766e80.png) *** ## 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). ![A/B testing](https://assets-site.prepr.io/w_1920/s3-preprmarketing/210a843a-fdb1-4e28-840f-b14ce6274a7d.png) *** ## 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. ![Mailgun](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9d7faca1-eec1-4404-90e1-cab42b3f509d.png) *** ## 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. ![Publication element](https://assets-site.prepr.io/w_1920/s3-preprmarketing/13ed4563-b5ad-419e-a90e-b0ba2fdc4a63.png) *** ## 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! ![Update Prepr](https://assets-site.prepr.io/w_1920/s3-preprmarketing/2ef693b9-b6af-42dc-af7f-b82f4e7d4837.png) **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 content filter](https://1v183a6gwww5.b-cdn.net/w_1920/s3-preprmarketing/53b19ebf-c2a2-44e8-aac5-6f48dd970274.png) **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. ![No follow tags](https://assets-site.prepr.io/w_1920/s3-preprmarketing/bc9372e9-8c4d-40d2-b172-90008e29631e.png) *** ## 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). ![Webhook trigger](https://assets-site.prepr.io/w_1920/s3-preprmarketing/42bbfa6a-6eed-4247-8370-9859f895f716.png) *** ## 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! ![Schedule days](https://downloads-site.prepr.io/52331a93-bdc2-4c72-a853-023aca7a04a0.gif) *** ## Publication elements as predefined publication fields *February 22nd, 2021* ![Publication content](https://assets-site.prepr.io/w_1920/s3-preprmarketing/cbe64103-f6ce-4d49-acc1-1171c0369e1c.png) 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. ![Component fields](https://assets-site.prepr.io/w_1920/s3-preprmarketing/de63d72f-87bf-44f6-8ae5-14dfaaea6961.png) *** ## 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). ![Seamless e-commerce](https://assets-site.prepr.io/w_1920/s3-preprmarketing/6065cd31-fecd-4846-b2f4-05177d00d01f.png) *** ## 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. ![Update scheduler](https://assets-site.prepr.io/w_1920/s3-preprmarketing/4d5b623e-380d-42d1-a7c3-6f0e4a9050d6.png) 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. ![AB Test](https://assets-site.prepr.io/w_1920/s3-preprmarketing/a5a9ed68-0b49-4954-af72-6f55ebf28338.png) - 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. ![Email notification](https://assets-site.prepr.io/w_1920/s3-preprmarketing/b20e6926-fb75-416e-b4f1-f5b242f9fddd.png) 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). ![Namibian locale](https://assets-site.prepr.io/w_1920/s3-preprmarketing/cafdbd61-f491-40b6-8553-582ffe665008.png) *** ## 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. ![List items](https://assets-site.prepr.io/w_1920/s3-preprmarketing/66b4d861-d1b5-4e3e-b02c-21bf6ae08ae3.png) *** ## 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. ![Multiple track notes](https://assets-site.prepr.io/w_1920/s3-preprmarketing/d6c7e84e-924b-4ff0-b26e-2da8a8b2b152.png) *** ## 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). ![Preview step](https://assets-site.prepr.io/w_1920/s3-preprmarketing/fe41a1ba-2ef6-4406-b8f9-edf66ca69a0f.png) *** ## 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. ![Resource element](https://assets-site.prepr.io/w_1920/s3-preprmarketing/5684beee-1de9-4a71-8713-5359c90bb095.png) *** ## 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. ![Import profiles](https://assets-site.prepr.io/w_1920/s3-preprmarketing/97788f40-f498-45c4-889a-258a51a45d72.png) *** ## 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. ![Publication status](https://assets-site.prepr.io/w_1920/s3-preprmarketing/5c3ae24d-5040-42e5-9ee7-e892217d2fbc.png) *** ## Add segment rules for ‘has full name’ yes/no *January 14th, 2021* ![Segment rules](https://assets-site.prepr.io/w_1920/s3-preprmarketing/95b09582-4c80-4da2-a4bc-ea5ab6c8f9ec.png) *** ## 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. ![Attention](https://assets-site.prepr.io/w_1920/s3-preprmarketing/a7d6cd3f-a43e-408e-a1be-2eb583146703.png) *** ## 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). ![Webhooks](https://assets-site.prepr.io/w_1920/s3-preprmarketing/bb984801-7488-4d61-873b-eb4c023ba598.png) *** ## 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. ![Contest and winner](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9b03919a-c584-4df2-95e2-1b55d3249869.png) *** ## # 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). ![Event types](https://assets-site.prepr.io/w_1920/s3-preprmarketing/22e99c05-a4eb-4207-aa94-e36b02eacda0.png) *** ## # 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. ![Email template](https://assets-site.prepr.io/w_1920/s3-preprmarketing/0b8f8856-b3f9-42d2-b60d-732217e3161a.png) *** ## # 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). ![Add model](https://assets-site.prepr.io/w_1920/s3-preprmarketing/dcb5eb9e-f935-417a-b6b6-58e8f92383f1.png) *** ## # 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). ![Publication links](https://assets-site.prepr.io/w_1920/s3-preprmarketing/8e60a8ab-d118-40c0-9be4-e24392c90666.png) *** ## Deprecated features - Notifications Source: https://docs.prepr.io/stay-updated/changelog2021 --- # Changelog 2022 Find the beautiful features and important updates that were added to Prepr in 2022. 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** | [2021](/stay-updated/changelog2021) ## Introducing Prepr Live Stream *Dec 15th, 2022* You can now create and manage live streams from Prepr, without the need for an additional streaming platform. Prepr is the first CMS in the world to offer a built-in live stream feature. Start streaming in seconds using Prepr Live Stream. Learn more [on our blog](https://prepr.io/blog/live-stream) or [follow our guide](/development/best-practices/assets/live-video-stream). *** ## Deprecating oAuth Apps *November 29th, 2022* OAuth is the authentication process Prepr uses to grant third-party developers secure access to Prepr customers’ data, via the API. Historically, we’ve used OAuth Apps (client credentials) but, to better serve our entire community, we’re moving to the industry standard using a static long-lived token. We’ve been communicating this since late 2019 and the change has come into effect. Existing apps are now converted to static long-lived tokens and the endpoints for refreshing an access token will now respond with the same token upon any request for that app. If you have any questions, please [contact our support team](https://prepr.io/support). *** ## Option to disable editing a slug value *November 24th, 2022* It is now possible to disable editing on Slug fields. Turn on the **Disable editing** toggle if you don't want a content editor to edit the slug value. In this case, you can only update the field through the API. ![Disable editing on slug fields](https://assets-site.prepr.io/w_1920/5g9tdzbk71ds-01-read-only-slug-field.png) Check out [Field types](/content-modeling/field-types) for more details. *** ## New navigation for Organizations and environments *November 7th, 2022* We are pleased to announce new navigation when switching between environments, or between an environment and the organization level. The organization level screens have also been renewed to make it clearer when you are working at the organizational level. The detailed changes include: - A new environments overview page to make it easier to manage your environments within your organization. - Renamed tabs on the organizational level, namely, *Shared schemas* and *Shared customers* to make it clearer when you want to manage schemas and customers at an organizational level. - We've also updated the environment switch to ease the transition between organizations and environments. See an example environments overview page below: ![environment overview page](https://assets-site.prepr.io//2cwvtlnaj2ix-envvironments-overview-page.png) See an example of the new environment switch below: ![environment switch](https://assets-site.prepr.io//5veps4cq3qh4-environment-switch.png) These are just a couple of several updates that we are releasing within the next few weeks to improve your user experience, so stay tuned! *** ## Slug field validation *October 26th, 2022* Publishing a content item without a slug value, for example, the slug was accidentally deleted, leads to broken links on a website. With this update, we’ve added a validation algorithm that prevents editors from publishing content items with empty slug values. It will help you to maintain link integrity across your site. To activate the validation check, go to the [Slug Field settings](/content-modeling/field-types#slug-field) in your model, click the **Validation** tab and turn on the toggle for **This field is required**: ![Slug field validation](https://assets-site.prepr.io/w_1920/1gmb591wzhkw-slug-validation.jpg) *** ## GraphQL API update *October 18th, 2022* - Added new filters for Integer, Float, Date, DateTime and Date Range fields. - Added popular sort for ContentItems query (multi type filtering). - Improved descriptions of fields and filters in the introspection schema. *** ## Release of a new Schema Editor *September 29th, 2022* We are excited to announce the release of the brand new **Schema Editor**. This editor enables you to define a content structure for your web app which consists of models, components and their related fields. Now, not only can you create models, components and fields a lot easier than before, it's also a lot quicker to navigate between models and components with an easy-to-access single view within the **Schema Editor**. When creating models, you can choose to use templates that will create models for you and there is drag-and-drop functionality making it a breeze to add and rearrange fields. Watch this [short video](/content-modeling/managing-models) on how to use this new feature or check out the [Create a model](/content-modeling/managing-models#create-a-model) documentation for more details. *** ## Introducing single-item models *September 29th, 2022* Previously, Prepr always allowed content editors to create multiple items for a model. It's now possible to restrict the content editor to only create one item for a model per environment, for example, for site settings or navigation. You can enable this feature when you create a new model. Note that it's not possible to switch an existing multi-item model to a single-item model and vice versa. For more details, check out the [Create a model](/content-modeling/managing-models#create-a-model) documentation and for the API details, check out the [Content item object](/mutation-api/content-items-create-update-and-destroy#the-content-item-object). *** ## Option to disable auto-generated unique slugs *September 29th, 2022* Prepr automatically generates unique slugs when you save a content item with a slug that already exists. It's now possible to disable this feature in cases where you want to prevent duplicate content items. A typical situation to use this feature is when you want to add content items through the API and don't want a content item to be added automatically if the slug already exists. In this case, if you disable the auto-generated slug option, the API will return an error response if the slug already exists. For more details, check out the [slug field type](/content-modeling/field-types#slug-field) documentation and for API details check out the [Content item object](/mutation-api/content-items-create-update-and-destroy#the-content-item-object). *** ## Getting all locales of a content item at once *August 15th, 2022* We have improved the content locale support in the latest GraphQL API version ([2022-08-15](/graphql-api/upgrade-guide#upgrade-from-version-2022-03-22-to-2022-08-15)). Now each content item has the *\_localization* field that contains all available locales for that content item. With this update, you can fetch and render multi-language content with a single piece of front-end code and seamlessly adapt your website to international audiences. Use the following query to get all the translations of your content item at once: ```graphql copy query { Page { items { id, title _localizations { _id _slug title } } } } ``` For more information, read [Localization](/content-management/localizing-content) and [API reference](/graphql-api/localization). *** ## Pre-fetching B variant data for A/B testing *August 15th, 2022* With the latest GraphQL API update ([2022-08-15](/graphql-api/upgrade-guide#upgrade-from-version-2022-03-22-to-2022-08-15)), we have added a new system field *\_ab\_testing\_variation* to content model configurations. It allows getting all content model fields for the B variant in your A/B test. You might need to pre-fetch the B variant data to run an A/B test on a static site. In this case, run the following query, and use the results to pre-initialize your call-to-action component with the known values during the site build. ```graphql copy query { Post( id : "76b42254-dfb0-4568-ae84-4800717d23df") { _id title # Returns the A variant. _ab_testing_variantion { _id title # Returns the B variant. } _ab_testing_active } } ``` Find out more in [A/B testing](/ab-testing/setting-up-ab-testing) and [API reference](/graphql-api/personalization-recommedations-ab-testing). *** ## Validation of third-party content inserts *August 14th, 2022* Prepr always takes care of your data safety. That is why we have improved the validation of third-party content inserts. From now on, you need to specify a 3rd party service domain in your content integration set-up to whitelist that service in Prepr. You can do it in your [remote source](/content-modeling/setting-up-a-built-in-remote-source) settings under **Schema → Remote sources**: ![Whitelist a domain](https://assets-site.prepr.io/w_1920/v1q2b8syfjg-whitelist-domain.jpg) This way, you can control which external sources your Prepr environment uses for content inserts. For more information, see [Integrations](/integrations). *** ## Marking required fields in component *August 11th, 2022* Now you can make any field in a component required to fill in by editors. To do that, enable the **This field is required** option under the **Validation** tab in field configurations when adding a new field to your component or updating an existing one. ![Component required field](https://assets-site.prepr.io/w_1920/s3-preprmarketing/41c37f9e-80ec-4eb4-bba8-2beac471792d.png) Once done, the required fields will be highlighted in the **Required** column on the component overview page and marked with the **Required** label in a content item. With this update, we have created consistency between models and components. In addition, it provides editors with a better user experience, and developers now have more granular control over components in Prepr. Read more in [Managing components](/content-modeling/managing-components). *** ## Improved password policy *August 8th, 2022* At Prepr, we believe that forcing a strong password policy is a crucial step in defending confidential user information. Therefore, we are introducing an updated password policy. New criteria are designed to create a strong password and include the following: ![Strong password criteria](https://assets-site.prepr.io/w_1920/1nxk9lw33fed-strong-password.png) When signing up or changing an existing password in Prepr, these criteria are mandatory for all users to keep accounts safe. *** ## Updated navigation titles *August 2nd, 2022* Based on user feedback we have renamed the titles of navigation items inside Prepr. We have renamed 'Publish' to 'Content', 'Engage' to 'Customers' and 'Analyze' to 'Engagement'. These new titles should make the purpose of each of these sections easier to understand. In addition, we have moved the Personalization page to the main menu. This change reflects our focus on the features for building personalized content experiences we offer. *** ## Automatically regenerate slugs *August 1st, 2022* When changing the title of a content item, you may also want to adjust the slug for the item to match the new title. Until today, this had to be done manually. We have added an option to regenerate the slug with the click of a button. Simply click the 'Regenerate' button next to any slug field. Clicking it will generate a new slug based on the slug conststruct you have defined. This new feature can be a great timesaver when you're adjusting slugs frequently. ![Regenerate slug](https://assets-site.prepr.io/w_1920/s3-preprmarketing/daea53d7-1143-4183-86ba-40ba97f8e24a.png) *** ## New column options for models and components *July 22nd, 2022* When working with smaller fields in a content model, the column option makes it easy to divide those fields over multiple columns. We have increased the maximum number of columns from 3 to 5 columns for content models in Prepr. This will make for a better editor experience if you need to display a lot of small fields, like fields for numeric values. ![Columns](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9ce80e6b-7b0b-4fc9-bbe8-901fb94ed787.png) In addition, we have added the column option for components as well. You can add up to three columns to any component. To add columns to a model or component, click the arrow button next to the 'Add field' button and select 'Add columns'. *** ## Added no-NB locale *July 22nd, 2022* We have added support for the no-NB locale. This locale is an addition to the, already existing, no-NO locale in Prepr. Bokmål (no-NB) is an official written standard for the Norwegian language, alongside Nynorsk. Locales can be set up from the organization settings page. This feature is available to organization owners and users with the environments permission. *** ## API Explorer for content items *July 18th, 2022* Content items in Prepr can now be opened in the API Explorer, which will generate a complete GraphQL query for the selected content item. Simply click the 'Open in API Explor' button on the right of the content item detail page. ![Open in API explorer similar items](https://assets-site.prepr.io/w_1920/s3-preprmarketing/6b27dd34-59f2-48af-9410-0eb7586b33d3.png) Clicking the arrow on the side of the button will also bring up the option to generate a query for [similar content items](/recommendations#querying-the-api-for-similar-items). These new features allow developers to generate queries easily and make testing the response of a query much faster. *** ## Performance improvements for managing content items *July 18th, 2022* We have rolled out an update to improve the performance of the 'Content' section in Prepr. This update brings significant performance improvements to common tasks in Prepr. For example, creating a new content item is now 50% faster, the list of content items loads more quickly and opening an existing content item is also much faster. This update improves the user experience for content editors. We are constantly working on performance improvements like these. *** ## Elements are now called Components *June 30th, 2022* We always try to use familiar terms in our interfaces to create an intuitive experience for our users. Therefore, we have renamed the Elements functionality in Prepr to Components. Components allow you to create a reusable sets of fields, which can be used in content items. This new name is more coherent with naming for similar concepts in other applications and should therefore be more familiar to new users. To learn more about Components, [learn about it on our documentation website.](/graphql-api/schema-field-types#components) *** ## Introducing Mux: next-level video and audio processing *June 22nd, 2022* We're introducing Mux for all new Prepr accounts and are raising the bar for video quality and delivery methods. Mux Video is an API for professional video and audio streaming. Your video and audio files will automatically be uploaded to Mux by Prepr. From there you can stream them using a few simple API calls. Your videos will look beautiful every time, on any platform and at any scale. No matter if your content gets 10 or 10,000,000 views, it will play instantly. Compared to our previous video and audio solution, Mux offers various performance improvements that result in a better user experience for both your customers as well as content editors working with video and audio content in Prepr. Uploading video content is now up to five times faster, resulting in a significantly faster editing experience for content editors. *** ## Indexing your content items for visitor recommendations *June 7th, 2022* You can use Prepr's built-in personalization engine to show related content by sharing recommendations based on user behavior or the item's characteristics. To start offering Similar content, it is important that your content is analyzed and grouped around common characteristics. As of today, this analysis takes place automatically with your new content. Write your content, publish it on your site, and our Prepr analysis tool takes care of all text calculations. Learn more about this new feature on [our blog](https://prepr.io/blog/introducing-ai-text-analysis-for-better-recommendations). Start offering similar content on your site or app immediately. [Learn more about our recommendation engine](/recommendations). *** ## Added SDK support for Vue 3 *May 25th, 2022* Vue 3 became the default Vue.js version in February of 2022. Therefore, we have updated our SDK to add support for Vue 3. The SDK now supports both Vue 2 and Vue 3. We have also updated our documentation to reflect this change. [Learn how to set up Prepr in your Vue.js application](/connecting-a-front-end-framework/vuejs). *** ## Clean up your customer database by merging profiles *May 18th, 2022* Ever noticed duplicate customers in your Prepr environment? Now there’s a way to fix that! We’re thrilled to tell you more. Prepr’s Customer Data Management feature is a great way to learn about user behavior and it’s the starting point for creating personalized experiences. Maintaining high data quality is critical to making this work. Due to a combination of data import methods, you may encounter duplicate contacts at times. This can lead to inaccurate data analysis, incorrect personalization, and reduced data quality. To fix this we recommend merging duplicate customers. That’s why we developed the new Customer Merge feature. [Learn how to use it in our user guide.](/data-collection/managing-customer-data-manually) ![Merge customers](https://assets-site.prepr.io/w_1920/s3-preprmarketing/e84e74c9-9535-4bc7-bba5-d349000f5e04.png) *** ## Exclude bots and spiders from event data and segments *May 10th, 2022* Bots are automated computer programs that click around in a browser, attempting to mimic humans, or to indexing the web. They can either run on servers in a data center such as Amazon Web Services or sometimes, on people’s personal computers that have been infected with malware or a virus (referred to as a botnet). As of today, Prepr excludes these bots from the capturing of event data. This means that no event will be created for the page visits of a bot or spider, no customer profile, and therefore no engagement score. [Click here for more information on how Prepr handles search bots, as well as a full list of all excluded bots](/data-collection/fundamentals#how-search-bots-impact-event-data). *** ## Set a user-friendly display name as a list option *April 7th, 2022* Today's update includes an improvement to the list field in models and elements. Previously, a list field consisted of only 1 value; a text line. This means that this field must be relevant for the editor in Prepr as well as for the developer who retrieves the list via the API. This sometimes proved to be a problem. For example, when the developer needs a key without spaces or characters, but this is valuable to the editor. Now, it is possible to add a key-value as list items. This allows you to give a list item a technical name (a unique identifier, a key) and a user-friendly value that you see in the Prepr content items (the data, the value). All existing list fields are updated to the new key-value format. ![List value name](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9facd751-080f-4ad3-bcec-13a64d157df4.png) *** ## Clarify help text for your editors with markdown *April 6th, 2022* The help texts for a field in a model or element are an instruction to the editors of your content. It is now possible to further clarify the instructions by making text bold or italic. You can do this by using markdown in the help text, such as \*\* and \_. Read more about the possibilities of markdown in help texts. ![Markdown helptext](https://assets-site.prepr.io/w_1920/s3-preprmarketing/9b9b131f-5fb2-4a32-ac32-0ae721003049.png) *** ## Added support for Catalan and Basque locale (ca-ES and eu-ES) *March 11th, 2022* Catalan and Basque 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). *** ## Rock-solid segmentation for online marketing campaigns is now possible *February 16th, 2022* Today's update includes an important extension to the segment builder in Prepr. Segments 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. As of today, it is possible to segment customers by UTM data (such as sources and campaigns), by referral URLs, and by the number of sessions. You can also segment by browser and device type. At last but not least, you can now segment people by everyone who signed up on your front end. This extension will be an important contribution to the personalization of your content. [Learn more about segments](/personalization/managing-segments). ![Segmentation](https://assets-site.prepr.io/w_1920/s3-preprmarketing/11f597ac-657a-445a-b39c-c7575b83007b.png) *** ## Introducing dynamic links to prevent broken URLs *February 15th, 2022* Today, we have a big update for you. This feature has been requested by a lot of editors and now we are happy to announce the release of dynamic links in Prepr. To manage content in a CMS you often use links to point to other pages. But what if the URL of a page changes due to a last-minute change, a site structure update, or URL edits for Search Engine Optimization? Then a dead link appears on your website. This is where dynamic links come in. It allows you to link to content items or assets with a dynamic link that stays in sync with the title or slug. The link is automatically updated when the title, slug, or URL changes. This way the link stays intact when you move or rename content, and you don't have to enter a URL yourself. With Dynamic Links, your URLs will always be correct! Isn't that convenient? [Learn more about dynamic internal links](/content-modeling/field-types#content-reference-field). *** ## Match a specific pattern in your text fields Today's update includes regex validation on text fields. It's now possible to validate whether the value of a field matches a specific regex pattern. For users’ convenience, a number of predefined regular expression rules are provided for the most common cases; email, URL, date (European and US), and time (12h and 24h). Learn more about regex validation on text fields. ![Regex validation](https://assets-site.prepr.io/w_1920/s3-preprmarketing/0ff1e0a6-42c2-4a96-bab8-3f0587cbe9c5.png) *** ## Predefine field inputs with initial values Initial values are predefined values that are set for specific fields in a content model. Today, we launched initial value support for the following fields: text (line, area, and HTML), number, list, color, and boolean. Initial values help you be more efficient in editing content by letting you focus on editing the primary content fields while secondary fields are pre-filled with the initial values you provided. Any field that contains an initial value is editable: you can change the pre-filled value and fill in the field with a different value. *** ## Format your content item with text alignment Text alignment is a feature that allows you to horizontally align text in a content item. It enables the composition of a content item using different text positioning on the whole or selected part of the item. Starting today, Prepr offers four options for customizing your items: left alignment, center, right alignment and justify. Simply click the alignment option, and the text is visible the way you selected. And, also, the API response contains a p style: ```html copy


``` You can enable or disable text alignment in the model and element fields. ![Text alignment](https://assets-site.prepr.io/w_1920/s3-preprmarketing/19d2d73e-8bed-4c19-9227-97d1f498fc6c.png) *** ## 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). ![Model and element design update](https://assets-site.prepr.io/w_1920/s3-preprmarketing/127dbd99-2434-4b86-bb72-95a6eae7ea64.png) *** ## 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. ![API names of your model](https://assets-site.prepr.io/w_1920/s3-preprmarketing/595c2a49-ba9e-4db8-bd42-90089c374228.png) *** ## 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. ![Personalize](https://assets-site.prepr.io/w_1920/s3-preprmarketing/ba06336a-a6ea-4b03-b40c-ff2c9fc18c46.png) Source: https://docs.prepr.io/stay-updated/changelog2022 --- # Changelog 2023 Find the beautiful features and important updates that were added to Prepr in 2023. This changelog gives you an insight into the most eye-catching releases during this period. [Latest](/changelog) | [2024](/stay-updated/changelog2024) | **2023** ## Ensure content integrity with our new unique field validation *November 21st, 2023* As you've requested, we've added a validation to check for unique field values in content items. This validation is available for [*Single line Text*](/content-modeling/field-types#text-field) and [*Number*](/content-modeling/field-types#number-field) fields. Not only does this prevent content editors from entering duplicate values, but it also means you don't need this additional check in your code when updating or inserting content items through the [Mutation API](/mutation-api/content-items-create-update-and-destroy). To activate this validation, simply enable the **This field must be unique** toggle under the *Validation* tab for the chosen field. When done, an error will be triggered when a content editor or an API request tries to save a content item with a field value that already exists in the same field in another content item in the environment. ![unique field constraint](https://assets-site.prepr.io//1evr715qqxu2-unique-field-constraint.png) *** ## Enable Personalization and A/B testing *November 16th, 2023* It is now possible to enable or disable personalization and A/B testing on a stack field. As a content modeler, this gives you more control over which content items can have personalization and A/B testing added to them. Limit these features to relevant models by enabling or disabling these features on the stack field in the model. ![Enable personalizatin](https://assets-site.prepr.io//26lvi8vkiq1f-enable-personalization.png) *** ## Choose workflow stage to trigger required validation *November 6th, 2023* As requested, we've added a feature for you to choose when to trigger the required field validation for content items. Previously, the editor could save content items without filling in required fields and they only got an error for missing required values when the workflow stage was updated to *Done*. This new feature gives you the flexibility to choose the workflow stages that will trigger the required field validation. In the **Settings → General** screen, simply choose the workflow stages of the content item that will trigger the required field validation, for example, *In Progress*, *Review* and *Done*. *Done* is selected by default. ![settings workflow stage](https://assets-site.prepr.io//6p1adcsndspk-settings.png) *** ## Enable Strict Mode to support TypeScript *November 6th, 2023* We are pleased to bring you a feature to enable *Strict Mode* on the GraphQL schema. This means you will get accurate TypeScript types from your GraphQL schema which in turn means simpler, cleaner and more consistent code when processing GraphQL requests. For example, the strict GraphQL type of `String!` will never be null as opposed to the `String` type. In the **Settings → Access Tokens** screen, enable *Strict Mode* for a specific GraphQL access token. ![Enable strict mode](https://assets-site.prepr.io//3byk8rf80x1m-enable-strict-mode.png) *** ## Integrate with Typesense for content searches *November 3rd, 2023* We’re happy to announce that you can now integrate Prepr and Typesense to provide users with fast and flexible searches across your web app content. Setting up the Typesense integration in your Prepr is easy. With just a few clicks, you can connect Prepr to your Typesense application, and Prepr will handle the rest automatically. ![Connect to Typesense](https://assets-site.prepr.io//6lr2ybxjn3yx-new-typesense-app.png) Check out the [Typesense integration doc](/integrations/typesense) for more details. *** ## Role permission to delete content items *October 12th, 2023* As requested, we've added a feature to set special permission for users to delete content items. This gives you more flexibility when defining roles for different types of content editors. Simply enable or disable the option **Allow user to delete content items** in the user role. ![delete option](https://assets-site.prepr.io//qj4ozsb2fg8-allow-user-to-delete-content-items.png) *** ## Purge access token cache *October 11th, 2023* It's now possible to purge content cache linked to a specific access token. This means that developers can make sure that API requests made with the purged access token will return fresh content when needed, for example when you need a real-time sync of new content related to an important product launch or you need to clear old versions of data in the case of a manual deployment. Simply click the **Purge token cache** button for the access token for which you want to purge the cache. ![purge access token](https://assets-site.prepr.io//500i8yq6n5cu-purge-token-cache.png) For more details check out the [GraphQL caching doc](/graphql-api/caching). *** ## Drafts for published content items *September 29th, 2023* We are happy to bring you a renewed workflow to publish your content items. Now you can make changes to already published content items without affecting the published version. You can then explicitly publish or schedule the content item when it's ready. This means that you have complete control over changing and republishing previously published content items. Once you've created a content item and want it published to the web app, simply click **Publish and close** to publish it right away. You can easily make updates to the published content item directly and then click the **Save** button. This will save the changes without publishing them. This means there'll be two versions; your saved version and the published version. ![publish content item](https://assets-site.prepr.io//30g11ef3nmmn-publish-a-content-item.png) You can still schedule your content items to be published at a later date, now with just a click of the **Schedule** button. Enter the *Publish on* date and click the **Schedule** button and that's it. You can also enter an *Unpublish on* date for temporary content. ![schedule a content items](https://assets-site.prepr.io//wvdbgrzk4d2-schedule-a-content-item.png) When publishing your content items, the workflow stage of the content item will be updated to *Done* automatically. For more details, check out the [Manage content item docs](/content-management/managing-content/managing-content-items#publish-a-content-item). *** ## Specify which text fields you want to automatically translate *September 12th, 2023* We recently added an AI-powered auto-translation feature to Prepr. While we've received a lot of positive feedback, some customers have expressed a desire for settings to skip or ignore auto-translation. This update allows users to specify which text fields should be ignored during automatic translation. ![Field AI toggle setting](https://assets-site.prepr.io//4tz6qdatdjjc-ai-toggle-setting.png) *** ## Check linked and unused assets *September 12th, 2023* We are happy to bring you a long-awaited update to the media library. It is now possible to check if an asset is being used in any content items. This view helps you when deciding which assets can be deleted. There is a new filter checkbox called *Unused*. When you select the *Unused* checkbox, all the assets that are not used in any content items will be shown. ![unused filter](https://assets-site.prepr.io//lbkdxzrzby6-unused-filter.png) Open a specific asset to see a list of content items that use this asset. ![Used in content items](https://assets-site.prepr.io//5qwiy014di0p-used-in-content-items.png) *** ## View system fields in the Schema Editor *August 1st, 2023* As requested, we've added a feature to view the system fields directly in the Schema Editor when editing or viewing a model. This gives you the benefit of having an overall view of a model and direct access to the *API ID* of a system field that you can use in your API query requests. Simply enable the **Show system fields** toggle at the top of your model to see the list of system fields. You can also see some help text and the *API ID* of each system field. ![view system fields](https://assets-site.prepr.io//456jv1u7rxp1-show-system-fields.png) Check out the [Model docs](/content-modeling/managing-models#view-system-fields) for more details. *** ## AI translation of content items now available *July 13th, 2023* We are very excited to bring you the option to auto-translate your content items using AI. This will lighten the workload for content editors who need to create translated copies of a content item. To use the new feature, go to the content item that you wish to translate. Simply, choose a language from the drop-down menu and click *Translate automatically using AI*. Choose a source language for the translation and that's it! The result is a machine-translated content item entry for the chosen language. You can then review and adjust the translation as needed before publishing. ![auto-translate](https://downloads-site.prepr.io/4xvm6tnheiy9-auto-translate.gif) Check out the [Localization doc](/content-management/localizing-content#working-with-multiple-locales) for more details. *** ## Support for multiple-asset and single-asset fields *June 30th, 2023* You can now choose between using a multiple-asset or single-asset field [when adding it to a model or component](/content-modeling/field-types#assets-field), depending on the number of assets you intend to add. A *single-asset field* only allows for a single image, video, audio fragment, or file to be added. The API response for this field type is simpler since the API doesn’t return an array of assets. A single-asset field might be a better fit for content items such as author profiles or contact pages. The *multi-asset field* allows for multiple assets to be added and is returned as an array by the API. You may want to use this field type for content items like articles and products. ![Multiple-asset and single-asset field](https://assets-site.prepr.io//79t4r4ic86nc-assets-field-type.png) This feature provides you with more flexibility in creating customized setups for your content and simplifies [querying assets](/graphql-api/schema-field-types#assets) using the API. Check out our [asset guides](/content-management/managing-assets) to learn how to add assets to your web app. To get this feature, upgrade you API to the latest version [2023-06-30](/graphql-api/upgrade-guide). *** ## New GraphQL API version released *June 30th, 2023* The latest version of the GraphQL API version, 2023-06-30, introduces a new recommendation algorithm to the API. All models now have a People Also Viewed recommendation query to serve your customers with content they are likely to enjoy and keep them engaged with your web app for longer. This release also simplifies the querying of images. An asset field can now be configured as a single-asset field, removing unnecessary arrays when using an asset field with only one asset. To take advantage of these features, upgrade to the latest version of the API. For more information, see the [upgrade guide](/graphql-api/upgrade-guide). *** ## Creating complex web pages is now easier with nested components *June 23rd, 2023* The introduction of nested components has made content modeling in Prepr even more powerful. In addition to adding a component to a model or Stack field, you can now [embed one component into another](/content-modeling/managing-components#create-a-nested-component), creating a parent-child relationship within a component. For instance, you can add a call-to-action component to a page header component: ![Nested component in a content item](https://assets-site.prepr.io//3749rg9z5d8x-nested-component-in-a-content-item.png) You can reuse individual components as many times as needed, even if they're already used within nested components. So you can use a call-to-action component in both a page header component and a product collection component. With nested components, your page elements can be customized even further, providing more options for users to engage with your content. Check out our [schema docs](/content-modeling) for more tips on how to build web page layouts of any complexity with ease. *** ## Redesigned Access Tokens page for a better user experience *June 5th, 2023* We’re excited to introduce a redesigned Access Tokens page in Prepr to bring you a more user-friendly and intuitive experience. With this update, you will be able to view the [permissions](/graphql-api/authorization#permissions) granted to tokens, as well as which token is currently in use in the [API Explorer](/graphql-api/test-queries). This will help you keep track of your tokens and ensure that you are using the correct one for your needs. In addition, we have also added a new feature that notifies you when a new access token becomes available. You will see the notification as an information badge on your existing token. It will help you stay up-to-date and have access to the most recent [API features](/graphql-api/upgrade-guide). Also, on the Access Tokens page, you can now copy the image and file domains to use them in your front-end framework add-ons, such as Nuxt Image, if needed. ![Access tokens page](https://assets-site.prepr.io//gkms434t5ba-new-access-tokens-page.png) If you have any feedback or suggestions for further improvements, please let us know in the [Slack channel](https://slack.prepr.io/) or by [contacting Support](https://prepr.io/support). *** ## Option to restrict a user role by locale *May 23rd, 2023* With this update, we've added a new feature that lets you manage user role permissions at a more granular level. You can now define the locales to which a specific user role has access. This is especially useful for those who work with a multi-language setup in Prepr and need to ensure that certain users have access to specific locales. For example, you can restrict a marketer of your Belgian brand to accessing only content in the nl-BE and fr-BE locales. To use this feature, [create a new role](/project-setup/managing-roles-and-permissions#add-or-edit-roles) and enable the *Content* permission. Then, select the necessary locales that the user role should have access to. If you want this user role to access content items of all locales, you can leave the field empty. ![Restrict user role by locale](https://assets-site.prepr.io//7ghrnm463iqe-roles-and-permissions-locales.png) *** ## Option to include a country, language, and optional fields in a slug template *May 22nd, 2023* When [adding a slug to a model](/content-modeling/field-types#slug-field), you can define which fields are used for slug generation. This update extends the list of available fields, making it easier to identify and memorize content item URLs. In addition to the existing *title*, *id*, and *locale* fields, you can now include the following: - *country* – adds the country code for a locale, such as *DE* for de-DE and *FR* for be-FR. - *lang* – adds the language for a locale, such as *de* for de-DE and *be* for be-FR. Also, the slug generation has become more flexible for slugs with multiple fields. If any of these fields are not required in a model, a slug can still be generated without those values. In other words, making a field optional in a model allows the field to be omitted when generating a slug. For example, if the slug template equals *`{title}/{authors.slug}`* and the author is not set, then the generated slug will only be the title value. ![Slug template](https://assets-site.prepr.io//73i7mm9kfbp4-slug-with-optional-fields.png) *** ## UX improvements for Environment settings *May 17th, 2023* As part of our ongoing efforts to improve user experience in Prepr, we have introduced several updates to environment settings. The changes include: - *General environment settings* were moved from the organization level to the environment level. This means you can now rename your environment and change its timezone and language settings with fewer clicks. Read more about [environments in Prepr](/project-setup/setting-up-environments). ![General environment settings](https://assets-site.prepr.io//6q7z0rdmodk-general-settings.png) - *Locales settings* were moved to a dedicated page for quick access to a multi-language setup. Here, you can choose available locales for your environment and set a default. Learn more about [content localization with Prepr](/content-management/localizing-content). ![Locales settings](https://assets-site.prepr.io//6yn42wufm9z5-locales-settings.png) - The *Apps* page was renamed to *Integrations* to better reflect its functionality. Here, you can connect your Prepr to a chosen 3rd party service. Explore available [integrations in Prepr](/integrations). *** ## Sign up to Prepr with your GitHub and Google accounts *April 28th, 2023* You can now use your GitHub or Google accounts to [create a new Prepr account](https://signup.prepr.io/) or log in to an existing one. This makes the sign-up process quicker and more convenient for you. Don't miss out on the opportunity to streamline your account creation process and start exploring all that Prepr has to offer. ![Sign up to Prepr](https://assets-site.prepr.io//2yagir6bvkgw-sign-up.png) *** ## Expanded range of languages for content creation *April 26th, 2023* Prepr has expanded the range of available languages with 41 new locales, including second languages of many countries. This provides editors with a greater choice when creating content for audiences around the world. No matter where your readers come from, whether it's Brazil, Italy, Norway, or Greece, they can find content that truly resonates with them. To learn more, please [refer to our localization docs](/content-management/localizing-content) and check out the full list of available locales in your Prepr environment settings. If you need a specific locale that is not listed, please [contact our Support Team](https://prepr.io/support), and we will add it upon request. ![Content locales](https://assets-site.prepr.io//4dvur8n0v97k-locales.png) *** ## View your Prepr content on the Patterns site *April 26th, 2023* We are happy to announce that you can now view a live website based on imported demo data, without writing a single line of code. Follow these steps below to view your content on the site: - After you have created an environment, choose to **Load demo data**. - Click the **View site** button. A new window will open and show the *Patterns site*. - Edit or add content for web pages, articles, live stream events and even a navigation with menu items using the imported models and components. Your content will be visible on the site in realtime. You are most welcome to clone and edit the Nuxt.js repository if you'd like to change the schema and see the results on your own localhost. You can also deploy the site using Vercel with just the click of a button. We’d love to hear your feedback on this feature through the [Prepr Slack channel.](https://slack.prepr.io/) ![view site button](https://assets-site.prepr.io//2rnil59z6tc1-view-site-button.png) ![patterns site](https://assets-site.prepr.io//40bmca3vk3qy-view-site-button-clicked.png) *** ## GraphQL API update *April 17th, 2023* The following updates to the GraphQL API help to keep queries clean and adds support options for analytics and SSR when using personalization and A/B testing. There is also a speed improvement especially for customers with complicated content models. - Added new field `_context` to models and components in a Stack. See the [API system fields](/graphql-api/schema-system-fields#personalization-and-ab-testing) and the [API reference docs](/graphql-api/personalization-recommendations-personalized-stack) for more details. *** ## Personalize content for 3rd party customer segments *April 7th, 2023* Delivering personalized experiences with Prepr has become even more accessible. You are no longer limited to customer segments created by Prepr when personalizing content. Now you can use segments maintained in any CRM or CDP system of your choice without importing customer data into Prepr. To use this feature, provide a *Segment reference ID* copied from your external system when [creating a new segment in Prepr](/personalization/managing-segments#use-external-segments-from-crmcdp-systems). Once you've personalized your content, call the API, passing the `Prepr-Segments` header in your API request. Read more about [using external segments for content personalization](/personalization#segments-from-external-crmcdp-systems). ![External segment](https://assets-site.prepr.io//5kg7ki24lo0l-external-segment-2.png) *** ## Improve Prepr content searches with Algolia *March 30th, 2023* We’re happy to announce that you can now integrate Prepr and Algolia to provide users with fast and flexible searches across your web app content. Setting up the Algolia integration in your Prepr is easy. With just a few clicks, you can connect Prepr to your Algolia application, and Prepr will handle the rest automatically. ![Connect to Algolia](https://assets-site.prepr.io//5o1t3xducpyh-connect-to-algolia.png) Once Prepr is connected to Algolia, it sends your content item data to Algolia. Whether you publish, update, or delete a content item, all the changes will be reflected in real-time in your search index via the Algolia Search API. This ensures that your users receive the most up-to-date search results. For detailed instructions on integrating Algolia, please refer to the [Algolia integration guide](/integrations/algolia). Please note that the Algolia integration is a paid option on top of your regular subscription and needs to be activated upon request. For more information, please [contact our Sales team](https://prepr.io/contact-sales). *** ## Introducing Dark Mode for Prepr *March 30th, 2023* We’re excited to announce that Dark Mode is now available in Prepr. So you can enjoy all the same functionality with your preferred appearance. When designing and developing dark mode, we focused on refining all UI elements for their color and contrast to help reduce eye strain and provide a comfortable viewing experience to our customers. - **Colors:** We use dimmer background colors and brighter foreground colors to ensure the interface has sufficient contrast. - **Text and Icons:** We display the text and icons in a contrasting color on a dark background to maintain high text legibility and image visibility. You can switch between dark, light, and system modes anytime. Hover over your Prepr profile icon and pick your preferred display setting. ![Dark mode](https://assets-site.prepr.io//26ebzdbprsxa-dark-mode.png) *** ## Upgraded model templates *March 28th, 2023* We are pleased to announce that we upgraded our model templates when you create a model. Now, it's even easier to set up commonly used patterns in Prepr such as *Page*, *Blog*, *Live stream*, *Navigation*, and *App config*. All you have to do is create a model and choose the pattern template. Prepr will then create the models and components that you need automatically. If the template you choose doesn't completely fit your needs, simply update the models and components according your requirements. ![Add-template-model](https://downloads-site.prepr.io/5w811fa1a2n3-use-model-template.gif) *** ## A/B testing update *March 23rd, 2023* As part of our ongoing improvements on existing features in Prepr, we bring you an update to the A/B testing feature. Now, it's even simpler to do A/B testing and you can A/B test parts of a content item instead of the whole content item. This is possible by using the *Stack field*. Check out the [stack field doc](/content-modeling/field-types#stack-field) for more details. Simply click the A/B test icon on the element in the stack, which could either be a content item or component. Duplicate the element and update the copy to create a Version B of the element. You can also run an A/B test with a single item. In that case, 50% of your users will see the selected item and the other 50% won’t see it. ![Add A/B test](https://assets-site.prepr.io//7ctk6jgtw4vl-b-test-in-stack.png) *** ## Sync two versions of a schema *March 10th, 2023* It is now possible to sync schemas between two environments in the same organization at the click of a button. This is useful, for example, if you have the most up-to-date version of your schema in the production environment and you want the schema version in the development environment to be updated to do testing with more realistic test cases. Check out the [Sync schema docs](/development/working-with-cicd/syncing-a-schema) for more details. ![sync schema results](https://assets-site.prepr.io//79ojkj26aesl-sync-schema-overview.png) *** ## Delete a language variant of a content item *March 8th, 2023* With this update, Prepr now offers an additional level of flexibility in managing content items. Content editors can now choose to delete the entire content item or a specific language variant. This is particularly useful when you need to remove unwanted content from only one locale without affecting the entire web app. [Click to delete a content item](/content-management/managing-content/managing-content-items#delete-a-content-item) and then choose a preferred option: ![Delete language variant](https://assets-site.prepr.io//5kjhlw59oj2u-delete-language-variant.png) *** ## Content item sidebar configuration *March 6th, 2023* We are happy to give you more control to help your content editors. You can now set up additional sidebar settings for content items. For example, if you want to skip reviews for some types of content items or publish them right away when saving. The following new options are available when you create or edit a model: - *Workflow:* If you disable this option, the *Status* and *Assignee* won't show up on the sidebar and content editors will directly publish a content item when they save it. - *Scheduling:* This option lets you choose whether or not content editors can schedule content items for publishing or archiving. - *Engagement insights:* This option lets you choose whether or not content editors can see engagement analysis in the sidebar. - *Commenting:* If you enable this option content editors can view and make comments for the purpose of reviewing content items. ![sidebar settings](https://assets-site.prepr.io//5pk1j5ngicj3-model-settings.png) *** ## Add subtitles to your Mux video assets *February 21st, 2023* You can now easily add subtitles to your Mux videos in Prepr to provide multilingual support to your web app visitors and extend the web app accessibility. To add subtitles, navigate to the needed video file in your *Media Library*, click **+Add Subtitle**, choose a locale, and upload either an *SRT* or *WebVTT* file containing the subtitle information. Prepr will automatically generate a subtitle URL and add it to the video in Mux. ![Add subtitle](https://assets-site.prepr.io//2h9drwg9bhsn-add-subtitle.png) There's no limit on the number of subtitle files you can include in your video asset. Each subtitle file will be stored as an individual file asset in Prepr. [Learn more about video assets in Prepr](/development/best-practices/assets/video-audio). *** ## Stack field with personalization *February 13th, 2023* We are excited to announce the release of the *Stack field*. A stack field is a field in which you compile a 'stack' of content items and components. This new field makes it much easier to structure and compose your component-based web pages. When you add this field in your models, you can combine content items and components in a single step when composing the content. The personalization process has also been streamlined and made more flexible. Now you can personalize items and components based on [customer segments](/personalization/setting-up-personalization) or countries within a content item. For example, set up the stack as follows: - In your schema, add a stack field to your page model and allow the applicable components and items to be added. - Add components or items to your page stack such as page headers and CTA's. - Finally, add segments and countries to personalize the components and items within your stack. Check out the [page pattern](/content-modeling/examples/page) doc on how to use a stack field and the [personalization](/personalization/setting-up-personalization) step-by-step guide for more details on setting up personalization within the stack. ![stack-field](https://assets-site.prepr.io//4nkijy29h23h-stack-field-with-elements.png) Also, Prepr has developed an automatic migration tool that allows upgrading the *Content reference* field to the *Stack* field without needing to change the front-end setup. You will see the **Upgrade to Stack field** button next to the content reference field if it exists in your schema. The **Upgrade to Stack field** button will only appear for a *Content reference* field with the *Modal* appearance setting. ![Upgrade to stack field](https://assets-site.prepr.io//6q6406w3g3ms-upgrade-to-stack-field-button.png) *** ## Embed Apple Podcast in your content item *February 13th, 2023* As of today, it is possible to use Apple Podcast as a social embed in Prepr. Choose Apple Podcast as a social field, or as an element in your dynamic content field. ![social field](https://assets-site.prepr.io//3kvhhwwo23s9-social-field.png) Add the URL of a podcast and Prepr generates a preview in real-time. ![podcast](https://assets-site.prepr.io//48enrzuiwqeh-podcast.png) *** ## Updated permission scopes for GraphQL access tokens *February 8th, 2023* Now you can define a permission scope per GraphQL access token more granularly. The new approach lets you choose which content item statuses are accessible for an access token. For example, you may want to get items that are still *In progress* or under *Review*. You can see the full permissions list in the screenshot below: ![permission scopes](https://assets-site.prepr.io//1hix7nb7lt-graphql-permission-scopes.png) Additionally, you can manage the GraphQL introspection setting. Disable it to prevent unauthorized users from accessing your schema, including types, fields, and queries. *** ## Improved usability for setting up content references *January 4th, 2023* We’re introducing a new design of the *Content reference* field in the Schema Editor and on the Content item page to make it easier to combine multiple content items on a single webpage. When you select allowed models, you can now choose whether editors are allowed to create new content items or not and whether to include content items from other environments for these specific models. So you get more flexibility with less effort. Check out the new options in the screenshot below. ![Content reference field in Schema Editor](https://assets-site.prepr.io/w_1920/6bhmvah6qy45-01-content-reference-field.png) We've also updated the look and feel of the Content reference field in content items when the Modal with search appearance type is selected. Instead of selecting create/search item first, editors now choose the model first to see a filtered list of content items. If the needed item is not present, editors can create it there and then. ![Content reference field in Content item](https://assets-site.prepr.io//6vqcikbhe0b7-02-content-reference-on-content-item.png) *** ## Improved 3rd party content integration *January 4th, 2023* With this update, we’re introducing *Remote Content* – an improved workflow for using 3rd party content in Prepr content items, for example, products from an e-commerce platform or job postings from a backend system. The setup process has become more convenient and faster thanks to our [new advanced *Schema Editor*](/changelog#release-of-a-new-schema-editor). You can now [set up a remote source](/content-modeling/setting-up-a-built-in-remote-source) and add it to the desired model within a single interface. ![Pre-built source fields](https://assets-site.prepr.io/w_1920/kuan9i8iqtb-02-fields-pre-built-source.png) To get started, check out our [Integrations guides](/integrations). Source: https://docs.prepr.io/stay-updated/changelog2023 --- # Changelog 2024 Find the beautiful features and important updates that were added to Prepr in 2024. This changelog gives you an insight into the most eye-catching releases during this period. [Latest](/changelog) | **2024** | [2023](/stay-updated/changelog2023) ## Introducing new embeds for Bluesky and Threads *December 23th, 2024* As requested, we're pleased to bring you two new embeds in your content: Bluesky and Threads, two rapidly growing social networking platforms. These embeds allow you to enrich your content with real-time updates from these platforms. By leveraging embeds from Bluesky and Threads, you keep your content relevant and make your content more appealing to web app visitors. Check out the [creating rich content doc](/content-management/managing-content/creating-rich-content#the-dynamic-content-editor) for more details. ## Prepr now supports Vercel Content Link *December 17th, 2024* We’re excited to announce that Prepr now supports *Vercel Content Link*. This feature allows you to edit website content directly from your preview website. By enabling *Edit Mode* via the toolbar, users can simply hover over elements to reveal links that open the corresponding item for quick updates — no developer needed. ![marketing site example](https://assets-site.prepr.io//256f1lmw809f-vercel-content-link-in-marketing-site.png) Check out the [Previewing doc](/project-setup/setting-up-previews#vercel-content-link) on how to activate the Content Link. ## New HubSpot integration: Adaptive content for HubSpot segments *December 16th, 2024* The new HubSpot integration allows you to create segments in Prepr based on HubSpot lists. Once this integration and relevant segment is set up, Prepr automatically adds the known HubSpot contact to the appropriate segment when they visit your website. ![HubSpot segment](https://assets-site.prepr.io//44r2mv11hhl9-segment-builder-conditions-hubspot.png) Your website can then render adaptive content for this visitor. Check out the [segments docs](/personalization/managing-segments) for more details. This integration is useful when HubSpot is a source for your segments, such as for specific campaigns or segments based on leads. This means you can seamlessly leverage these existing segments to deliver adaptive content directly in your website. Enhance your engagement strategy by providing adaptive content for contacts from HubSpot campaigns. Check out the [HubSpot doc](/integrations/hubspot) on how to activate the integration. ## Adding time filters to event conditions in a segment *December 16th, 2024* As part of our ongoing efforts to enhance the adaptive content features, we've extended the segment event conditions with a time filter. Now you can add a time filter when adding an event condition to target customers who interacted with specific pages. For example, to segment customers who visited a landing page in the last month. ![time filter in event conditions](https://assets-site.prepr.io//97b7yln0ieg-time-filter-in-event-conditions.png) This precise segmentation allows you to identify and engage with customers based on their recent activity or interest. By leveraging these insights, you can improve engagement and conversions by targeting the right audience at the right time. Check out the [segments doc](/personalization/managing-segments#time-filter) for more details. ## New Day and Time context filters in segment designer *December 16th, 2024* We're happy to announce an extension to the segment designer context selection. You can now choose one or more days or times when customers visit your website. ![day and time context](https://assets-site.prepr.io//2l1uqgkswxdx-day-and-time-context.png) Creating segments with these filters allow you to target customers with special time-specific or day-specific content such as discounts/promotions. For example, offering discounts to customers who make purchases on the weekend. Check out the [Segments doc](/personalization/managing-segments) for more details. ## Improved media browser *December 13th, 2024* We’re happy to introduce a new workflow for adding assets to content items with an improved media browser. When you add assets to content items, you now have the option to drag and drop an asset directly into your content item. ![Add assets to content items](https://downloads-site.prepr.io/5qrjkyuwpy8f-adding-assets-to-a-content-item.gif) Other than the clearer asset upload options, you'll notice more intuitive image cropping. This streamlined process allows you to manage assets directly while editing your content, making everything faster and easier. We've cut out all the extra clicks, letting you focus more on your core tasks to create impactful content. Check out the [assets doc](/content-management/managing-assets/editing-and-configuring-assets) on how to edit and configure assets in your content items. ## New GraphQL API version 2024-12-05 is available *December 5th, 2024* The GraphQL API has been updated with the following additions: - There is a new default `_json` field in the Remote Source type that contains the raw data content for the remote source. - The API now supports single-item Remote source fields. - It also supports two new embed types, `BlueskyPost` and `ThreadsPost`. - The API allows you to filter *Stack* fields in a model by the *Typename* of a component in the stack. Check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide#version-2024-12-05) for more details. ## New HTTP header context in the segment designer *December 5th, 2024* Once again, we bring you an update based on your feedback: The new *HTTP header* context option in the segment designer. You can now segment customers based on a context related to the web app that customers use. For example, to display specific content to customers based on the app version they're using. This means you can deliver precise content, such as version-specific content, to customer segments, supporting seamless feature rollouts or phased updates. ![HTTP header example](https://assets-site.prepr.io//4v05roi5iedb-new-http-header-context.png) Check out the [segment designer docs](/personalization/managing-segments) for more details. ## Update existing content items when adding fields *December 2nd, 2024* We're excited to bring you a new option to streamline your workflow when adding new fields. Now, when you add a *Text*, *Number*, *Boolean*, or *List* field to a model and set the **Initial value**, Prepr allows you to update all existing content items with one click. ![confirmation modal](https://assets-site.prepr.io//1rc5f8ys0g6n-new-apply-modal.png) You no longer need backend scripts to bulk update the related content items when adding new fields to a model. This feature not only saves you time but reduces the risk of missing content and potential site issues. For more details, check out the [field types doc](/content-modeling/field-types#text-field). ## Reassigning a duplicate content item *November 19th, 2024* As requested, we've made creating similar content items even more efficient. From now on, when you duplicate a content item, it's automatically assigned to you. This also means no more unnecessary notifications for others. For more details on editing content check out the [Managing content items docs](/content-management/managing-content/managing-content-items). ## New Segment Designer *November 8th, 2024* We’re thrilled to introduce the new *Segment Designer*, a major product update shaped by your feedback on the Prepr personalization feature. The *Segment Designer* helps you segment your audience with greater precision, improving visitor experiences that lead to higher engagement and conversions. ![segment builder](https://assets-site.prepr.io//4l8xgdbth5g4-segment-builder-with-context.png) Now when you create customer segments, you can set up more precise conditions, and define a current context for the segment. The *Context* of a segment includes current info about the customer, like the device they're using or the country they're in, when they interact with personalized content. To align with the new *Segment Designer*, we've made some minor updates when you add *Adaptive content* to a content item. The *Country* selection based on a visitor's geolocation has been removed. You can now set this up in the *Context* of the segment instead. These changes ensure that your segments in the Adaptive content are consistent with the segments that you've built. Let's take a look at new features in more detail: - Logical operators Previously, multiple conditions in the same segment were processed as mutually inclusive (AND), so it was more difficult to set up independent conditions for the same segment. Now you can explicitly choose the logical operators `AND` or `OR` to combine conditions exactly the way you need them. - Streamlined UI for easier segmentation The *Segment Designer* has a more intuitive design that makes it easier for you to build segments. As you set up conditions, they now form clear, logical sentences making it easier to see exactly which groups of customers are included in your segments. - New filter options - *Event frequency:* Segment customers who, for example, viewed a page more than three times. - *Event with content reference:* Target customers based on a referenced content item, such as an article by a particular author. - *Event for specific models:* Create segments for customers who viewed types of content like blog articles. - *Previous session:* Segment based on customers who last visited within a specific time frame, like the past 30 days. We're confident that this update makes segmenting your audience much simpler and more intuitive, while giving you the option to be more precise with your personalization. For more details on how to build customer segments, check out the [Segments doc](/personalization/managing-segments). If you have more suggestions on how we can simplify your experience with Prepr, [we'd love to hear from you.](https://docs.google.com/forms/d/e/1FAIpQLSf2kANsW0MRMOsETQVE5Ac6ikVyJqz7Zi7yes86aKaC9oFf5w/viewform?usp=pp_url) ## New visual model and component selection *October 28th, 2024* Great news for content editors! The new visual model and component selection solves the following challenges when adding content to your web pages: 1. Many components have technical names, like a *Call to action* component. 2. The list of content items and components is often very long for you to scroll through. Now when you choose a content item or component in a stack or reference field, you'll see a visual preview of what your content item or component could look like. You can also easily find content items or components by a tag which shows you a logical grouping, such as *Articles*. ![improved selector](https://assets-site.prepr.io//3nrexkzq1afi-stack-field-model-and-component-selector.png) We trust that you'll enjoy this more intuitive selector that boosts productivity when editing content. To make the preview images and tags available, developers can upload preview images and define relevant tags, where needed, directly in the model or component settings. Check out the [model settings](/content-modeling/managing-models#appearance) or [component settings](/content-modeling/managing-components#appearance) for more details. ## New dwell time metric *October 15th, 2024* We are excited to introduce the new dwell time metric for your A/B tests and adaptive content. Until now, you could only track their results with surface-level metrics such as the number of impressions and conversions. While these metrics provide good insights into visitor behavior, in some cases you need a better insight into user engagement of some elements on a page, especially when you're not tracking any clicks. With the new dwell time metric, you can track the average amount of time that customers view a specific element on a page, giving you this deeper insight. When used in A/B testing, dwell time allows you to compare the effectiveness of different versions of content. For example, if variant A of a *Product description* holds the user’s attention for an average of 45 seconds, while version B only captures 20 seconds, it's obvious that variant A is more effective. ![dwell time metric](https://assets-site.prepr.io//3f8sq2hcc8yr-new-dwell-time-metric.png) Check out the [A/B testing guide](/ab-testing/running-ab-tests#evaluate-the-ab-test) or the [Adaptive content guide](/personalization/managing-adaptive-content#evaluate-the-personalized-variants) for more details. ## New GraphQL API version 2024-10-04 is available *October 4th, 2024* The GraphQL API has been updated to support the single-item [*Stack*](/graphql-api/schema-field-types#fetching-a-single-stack-field) and [*Content reference*](/graphql-api/schema-field-types#fetching-a-single-content-reference-field) fields. It also includes a change to retrieving an A/B test with only an A variant. A/B tests without a B variant will now return no element for B targeted visitors, instead of defaulting to A. Check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide) for more details. ## Filter assets by enumeration values *October 1st, 2024* You can now filter your assets by specific enumeration values, making it even easier to find the ones you need. For example, filter assets by an enumeration field *License holder* to find videos or images that belong to certain companies. ![assets enum filter](https://assets-site.prepr.io//717d441p2wtq-media-page-enum-value-filter-example.png) This enhanced filtering allows you to quickly and easily locate the assets you need, boosting your productivity. Check out the [managing assets doc](/content-management/managing-assets/managing-assets#finding-assets) for more details. ## Choosing a component title *September 27th, 2024* Normally, the title of a component in a *Stack* or *Dynamic content* field is set to the first text element in your component. But, based on your feedback, we’ve made things a bit more flexible. At times, you may want the component title to be the title of a referenced content item. For example, when the embedded component title should be the headline of an article. Also, a component might just have a *List* or *Number* field, and in those cases, you might want the component title to be the chosen list item value or the number entered. For example, a number of the item that defines its order in a list. ![Set number field value as component title](https://assets-site.prepr.io//fbtxuyn85mb-set-number-field-value-as-component-title.png) As a developer, you now have the option to set the component title to these values instead, giving you more control and flexibility. This means the content editor sees clearer and more meaningful component titles in their content, making their content more understandable at a single glance. Check out the [components doc](/content-modeling/managing-components) for more details. ## Single content reference field and single stack field *September 19th, 2024* As a developer, you can now configure a single content reference field and a single stack field. This setting limits the content editor to adding just one referenced content item to a content reference field and just one referenced content item or component to a stack field. For example: If an article should only have one author. ![stack field settings](https://assets-site.prepr.io//3o3wr7jjf389-stack-field-settings.png) If you change a content reference or stack field to a single type, you'll get a warning to change existing queries in your front end. The single, flat structure reduces data complexity, making API queries faster and simpler. This means improved performance and quicker data retrieval, so you can focus on building with less overhead. Check out the [API field types doc](/content-modeling/field-types#content-reference-field) for more details. ## Choosing your own conversion event *September 18th, 2024* Until now, your metrics data for *Adaptive content* and *A/B testing* was based on the `click` event. With this update, you can now choose the event which represents conversions for you. Check out the [A/B testing doc](/ab-testing/setting-up-ab-testing#add-html-attributes-to-track-impressions-and-conversion-events) on how to send your conversion event to Prepr, such as a custom event for quote requests. With the new event filter in the metrics modal, you can choose to view metrics by the conversion event that matters to you. ![conversion event filter](https://assets-site.prepr.io//5kulg87oy0ph-ab-test-metrics-conversion-event-filter.png) This means you’ll be making optimization decisions based on even more precise and relevant data, helping you drive better results. ## Introducing Bitbucket Schema Sync *September 13th, 2024* In addition to the *Direct*, *GitHub*, and *GitLab Schema Sync* options, you can now choose to sync the schema using Bitbucket. If your preferred tool is Bitbucket, you have control over the sync process to manage schema updates exactly the way you need. ![sync schema modal](https://assets-site.prepr.io//u9aphs7m10a-sync-schema-modal.png) Check out more details in the [syncing a schema doc](/development/working-with-cicd/syncing-a-schema). ## New Technical contact role *September 11th, 2024* With the new *Technical contact* role, you can add your technical admin team members to Prepr. They can then be contacted directly for any incidents related to failed webhooks, or remote sources that are not syncing. Any announcements from the Prepr status page will also be emailed to them automatically. This means a quicker collaboration and response to solving incidents. Check out the [roles and permissions doc](/project-setup/managing-roles-and-permissions) for more details. ## New help text display option *September 10th, 2024* We’ve added a new way to show help text in content items. Instead of displaying the help text in small font below each field, you can now have it appear as a tooltip when editors hover over the icon next to the field name. ![help text example](https://assets-site.prepr.io//4x5z5ckvevhp-example-help-text-toolip.png) This option makes longer help text more readable and keeps content items uncluttered. Content editors can quickly check the help text when they need it, without it getting in the way. ## Overview of linked content items *September 10th, 2024* We've added a new sidebar option to the content item detail page that shows where this content item is referenced. You can now easily find and view linked content items. When you try to delete a content item that is referenced in other content items, you'll get a warning about the linked items. This means you can avoid broken pages when deleting a content item with linked items. For example, find all articles linked to a specific author from their detail page. ![sidebar linked items](https://assets-site.prepr.io//tbyuhztz96-sidebar-linked-items.png) ## New content view: Adaptive content and A/B tests *September 9th, 2024* With more users adding A/B tests and adaptive content in Prepr, and thanks to your valuable feedback, we've introduced a brand-new view to the content items overview page. Now, you can easily see all content items with adaptive content and A/B tests at a glance. It’s faster and simpler to find exactly what you're looking for. You can also filter this view further by the **Status** (*Active* or *Inactive*), **Type** (*Adaptive content* or *A/B test*), the content item **Model**, and the **Language**. ![adaptive content](https://assets-site.prepr.io//1nxyst26047i-new-content-view.png) Check out the [content items doc](/content-management/managing-content/managing-content-items#content-views) for more details. ## Block AI bots from scraping assets *September 5th, 2024* We've implemented an update to block all AI bots from scraping your video and document files from Prepr *Media*. This reduces the amount of bandwith you use. If you want to enable access to that content for those bots, ask the Prepr account owner to [contact our Support Team](https://prepr.io/support) to enable this. ## New API option to open files in the browser *September 5th, 2024* When you request files in a GraphQL API query, they are downloaded by default. With this update, you can now include a URL argument, `inline` with a value of `true` to display the file contents in a browser instead. This means that you get the file exactly the way you need to deliver it to your visitors. Check out the [GraphQL docs](/graphql-api/schema-field-types#files) for more details. ## Organize your enumerations into schema folders *August 27th, 2024* It's now possible to organize your enumerations into folders like you can with models and components. When you have dozens of enumerations, these folders make it easier to find related enumerations instead of scanning a long alphabetical list. For example, when you have multiple enumerations needed for the same components. ![enumerations folder](https://assets-site.prepr.io//3e1n2w2rj402-create-new-folder-modal-enumerations.png) Check out the [enumerations doc](/content-modeling/managing-enumerations#organize-enumerations-into-folders) for more details. ## Exclude IP addresses from data collection *August 27th, 2024* We've added a feature in the event tracking settings that lets you exclude specific IP addresses from data collection. This helps you maintain the integrity of your analytics by ensuring that actions like impressions and clicks from those IPs are not tracked. By filtering out internal traffic, you can keep your data clean, which is crucial for accurate AB testing and decision-making. ![exclude IP addresses](https://assets-site.prepr.io//7481rb8qkcyj-exclude-ip-addresses.png) Check out the [collect event data docs](/data-collection/setting-up-the-tracking-code#excluding-ip-addresses) for more details. ## Filter content items by enumeration values *August 26th, 2024* You can now filter your content items by specific enumeration values, making it even easier to find the items you need. For example, filter *Product* content items by the *Size* to find large T-shirts. ![enum filter](https://assets-site.prepr.io//74f98beeu5dz-example-content-items-filtered-by-enum-value.png) This enhanced filtering allows you to quickly and easily locate the content you need, boosting your productivity. Check out the [filter content items doc](/content-management/managing-content/managing-content-items#filter-content-items) for more details. ## Schema sync upgrade *August 22nd, 2024* We've upgraded the *Schema Sync* and added the *GitLab Schema Sync*. With the improvements to the Schema Sync process, you'll see better error handling and can now preview changes before completing the sync. In addition to the *Direct Schema Sync* and the *GitHub Schema Sync* options, you can now choose to sync the schema using GitLab. This upgrade gives you more control over the sync process to manage schema updates exactly the way you need. ![Schema sync modal](https://assets-site.prepr.io//77tnaqkgt1lp-sync-schema-modal.png) Check out the [Schema sync doc](/development/working-with-cicd/syncing-a-schema) for more details. ## Improved schema import and export processes *August 22nd, 2024* As part of our continued efforts to improve existing Prepr features, we've updated the import and export of models and components. The import and export logic has been updated to match the *Direct Schema sync* process to ensure consistency of models and components during the individual import/export processes. In addition to this improvement, it's now also possible to import and export individual enumerations and remote sources. When you only want one or a couple of enumerations or remote sources created in a test environment then you no longer have to create them manually. The improved import and export keeps your data structure intact. This means your schema integrity is maintained even when importing complex models or components with embedded elements and reference fields. This, in turn, means more accurate testing. For more details, check out the [Schema docs](/content-modeling/managing-models#export-and-import-a-model). ## User management updates *August 22nd, 2024* We've made some improvements to the user management feature. In particular, the following updates are now available for Agency users: - 2FA is now required for added security when managing client environments. - Agencies now have to manage permissions for agency users at agency account level. It’s no longer possible to manage agency users at the organization or environment level. - Agencies can now create their own custom roles that can be used in all client environments. - Permission to view the audit logs are now available to all agency accounts. The updated user management improves control for agency users, provides better oversight and gives more flexibility when managing their client users and permissions. Check out the [manage users doc](/project-setup/managing-users#agency-accounts) for more details. ## Introducing Metrics for A/B Testing and Personalization *August 6th, 2024* Prepr is a headless CMS with A/B testing and personalization features. Until now, it was only possible to measure A/B testing and personalization in external analytics tools. Based on feedback from our customers, we've implemented the option to track impressions and conversions to help you determine the results of your optimizations. Now you can see these results directly in Prepr. This means you gain insights into the impact of your experiments quickly and easily without needing other analytics tools. You can then use these insights to continuously improve customer satisfaction and conversion rates. Moving from biased design decisions to fact-based design decisions. It's now possible to set up your front end to send data to Prepr for metrics. For more details on how to set up your front end to trigger metrics calculations in Prepr, check out the [A/B testing doc](/ab-testing/setting-up-ab-testing) or the [Personalization doc](/personalization/setting-up-personalization). When metrics data is available you can view the results from your A/B test or personalization group. You can then filter the results by a chosen date range (defaulted to the last 90 days) or by a chosen segment in the case of A/B testing. The following metrics data is available: - Number of impressions - Number of conversions - Conversion rate - Standard error - Uplift - Probability that a particular variant performs better than the control. - Simple graph view of results ![A/B testing metrics example](https://assets-site.prepr.io//74zlkep2ua21-ab-test-metrics.png) For details on how to intepret the metrics, check out the [Run A/B tests doc](/ab-testing/running-ab-tests) or the [Personalize website doc](/personalization/managing-adaptive-content). The Metrics feature can be used successfully from GraphQL API Version 2023-04-17. If you have an older GraphQL API version, check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide#how-to-upgrade-to-a-newer-graphql-api-version). If you have more suggestions on how we can simplify your experience with Prepr, [we'd love to hear them!](https://docs.google.com/forms/d/e/1FAIpQLSf2kANsW0MRMOsETQVE5Ac6ikVyJqz7Zi7yes86aKaC9oFf5w/viewform?usp=pp_url) ## New Settings for A/B Testing and Personalization *August 6th, 2024* We're happy to announce new settings available for your A/B tests and personalization. Previously, each A/B test variant was shown to 50% of customers. It's now possible to modify the percentage of traffic allocated to each variant during an A/B test. This means you can optimize your experiments for more accurate results. So, it ensures faster decision-making. Check out how to manage this setting in the [A/B testing guide](/ab-testing/running-ab-tests#manage-the-ab-test). ![change traffic distribution](https://assets-site.prepr.io//18uem5k9utzw-change-traffic-distribution.png) Previously, a query for a content item with personalization only returned the first matched personalized element. It's now possible to enable the API to return all the matching personalized elements instead. For example, when there are multiple FAQ items that include the same segment. This allows you to choose which personalized elements are shown in the front end, meaning more relevant content. Check out how to manage this setting in the [Personalization guide](/personalization/managing-adaptive-content#manage-the-personalization). ![Manage settings](https://assets-site.prepr.io//7b1vtkp8n4q2-personalization-manage-settings.png) ## New SEO field options for components *August 5th, 2024* Previously, you could only set model text fields as SEO titles or meta descriptions. Now, you can mark text fields in components as SEO titles or meta descriptions, like you can in models. This means you can manage your SEO attributes consistently across your schema. In so doing, you improve the visibility and ranking of your content more efficiently, leading to better search engine performance and increased web traffic. ![SEO fields for components](https://assets-site.prepr.io//1uajh5fp1x1t-new-seo-field-options-for-components.png) Check out the [Text field doc](/content-modeling/field-types#item-title-and-seo-fields) for more details. ## Disable content item deletion *August 5th, 2024* Based on your feedback, we've added a setting that disables content item deletion for a model. When active, this setting prevents editors accidentally deleting content items. Now you don’t have to worry about content editors removing content items that store important system information, such as *App configuration* like global meta tags and copyright info. ![disable delete setting](https://assets-site.prepr.io//5h02re8bguiu-model-disable-delete-setting.png) This update makes working with Prepr even smoother. If you have more feedback on how we can simplify your experience with Prepr, [we'd love to hear from you!](https://docs.google.com/forms/d/e/1FAIpQLSf2kANsW0MRMOsETQVE5Ac6ikVyJqz7Zi7yes86aKaC9oFf5w/viewform?usp=sf_link) ## New Billing role *July 16th, 2024* A new default user role, Billing, is now available. This role grants access to the organization's plan and billing information, enabling users to manage payment details, view and handle invoices, and oversee subscription details. Billing users do not have access to other administrative or content-related functions within the environments or organization. For more information on the new Billing role and its capabilities, please refer to our [updated documentation](/project-setup/managing-roles-and-permissions). ## Improved access token management *July 16th, 2024* As requested, we've made a couple of updates to improve the management of access tokens. It's usually very useful to open the *API Explorer* directly from a content item to perform GraphQL queries. By default, this API Explorer connects to the first access token when the environment was created. Previously, you couldn't change this default access token. With these new UI updates, you can now switch the default access token for the **Open API Explorer** button. Also, now you can just hover over each access token to **Edit**, **Delete**, or **Use for API Explorer**. ![Access token list actions](https://assets-site.prepr.io//1ybpsdj10fvw-access-token-list-page.png) This improvement makes managing access tokens more intuitive and efficient. Switching access tokens ensures the API Explorer uses the most up-to-date token. These updates give you more flexibility and control and managing access tokens is now easier and more user-friendly. ## Improving environment stage visibility *July 10th, 2024* Some of our customers manage multiple Prepr environments. In this situation, there are times when users accidentally make updates in the wrong environment. That is why we've made minor UI updates to make it clearer to users which environment they're currently working in. We've updated the environment dropdown selector and added a new label at the top of the screen to indicate which non-production environment you're currently working in. This helps users who frequently swap between staging and production environments and reduces the risk of making updates in the wrong environment. ![new staging label](https://assets-site.prepr.io//7942zb22q9qa-staging-label.png) ## Environment-to-environment Content Export *July 5th, 2024* We are very proud to bring you the most requested feature by developers, the *Environment-to-environment Content Export*. With the *Environment-to-Environment Content Export*, you can easily copy content across different environments. This streamlined process reduces your dependence on Prepr support, significantly saving time. By maintaining current content for development and testing, you improve collaboration with marketers and editors for more accurate testing of realistic scenarios and ensure superior quality assurance, ultimately accelerating your project timelines. The *Environment-to-environment Content Export* goes hand-in-hand with the *Schema* sync process which should be run first to make sure that content is exported to a valid schema. Check out the [Schema sync docs](/development/working-with-cicd/syncing-a-schema) for more details. As a developer, you can select specific content items you want to copy over to another environment. Trigger the content export with the **Export to** action available in the Content item list page. You can copy content between any two environments you have access to in the same organization. Check out the [Export content doc](/development/working-with-cicd/syncing-content) for more details on the process and troubleshooting errors. ![Export content modal](https://assets-site.prepr.io//1ken55nzch3m-content-export-modal.png) ## Introducing sharing of filtered lists with URL *July 5th, 2024* Sometimes, you may want to share a filtered list of content items with a team member. However, this was previously not possible because the URL did not contain the filter parameters. We've now added these parameters. This means you can simply copy and share the URL with your team. This small enhancement makes collaboration easier. ## Introducing collapsible components in the Dynamic Content field *July 5th, 2024* We have great news for those who use components in the Dynamic Content field. It is now possible to collapse individual or all components in dynamic content fields in your content, reducing clutter and providing a clearer overview. Previously a dynamic content field with a lot of components could become chaotic to manage. Now it's easier for you to manage and focus on the specific content that needs editing, enhancing your workflow efficiency and making the editing process more intuitive. ![collapsible components](https://assets-site.prepr.io//4rzsgtwbz1ms-collapsible-components-in-dynamic-content-field.png) ## Added Text Filter Option to Remote Source *July 4th, 2024* Upon customer request, we've added a text (`string`) filter to the list of filter options in a custom remote source. You can now set this filter in the custom remote source feed and it'll become visible when an editor adds a remote item, allowing them to filter by text. For example, by a category name. Check out the [custom remote source doc](/content-modeling/creating-a-custom-remote-source#step-1-set-up-your-custom-api-endpoint) for more details on how to set up an endpoint with filters. ## New heading display options in HTML fields *July 4th, 2024* Today, we bring you new heading display options for HTML fields. These new options allow you to configure display options for the HTML text field headings, by giving you the flexibility to choose which headings (`H1` to `H6`) are available to editors. ![heading display options](https://assets-site.prepr.io//3t0p9so31nfu-heading-options-settings.png) Previously, all heading options were available to editors which sometimes caused styling inconsistencies in the front end. For example, now you can ensure that key headings, like `H1`, are reserved exclusively for article titles. By providing this level of control, this setting supports the alignment of content with the website's design and editorial standards, enabling more effective content management. Check out the [Text field doc](/content-modeling/field-types#text-field) for more details. ## New component display option *July 2nd, 2024* Based on the results from our user research, we've implemented new component options that define how component fields are displayed in a content item or in another component. You can now choose to display component fields grouped or ungrouped in content items. ![component setting](https://assets-site.prepr.io//6blpz2v841yc-component-settings.png) Previously, the display of component fields were always grouped with the name of the component at the top of the group. For some components, it's cleaner and avoids confusion by displaying the fields like any other content item field. Now you can display component fields seamlessly with other content item fields. For example: An *Image + Caption* component that has an image field and caption field. ![image and caption](https://assets-site.prepr.io//305q9gnwpr14-display-component-fields-as-group-vs-not-grouped.png) However, an SEO component is a good example of where grouping all SEO-related fields is sensible, to differentiate them from other fields in the content item. Check out the [Component field doc](/content-modeling/field-types#component-field) for more details. ## Content item search improvement *June 18th, 2024* We've implemented a change to the content item *Search* functionality. Previously, the content item search scanned through all the text in each content item, by default. With this change, it now does a narrowed down search on the content item *Title* by default. This improves the quality of the search results and the performance of the search when you have thousands of content items. It's still possible to search through the *full-text* of content items by explicitly choosing this option when you click on the search bar. The same goes for searching on the *Slug* or *ID* fields of the content items. ![content item search](https://assets-site.prepr.io//4xpmo6bg5i1y-content-item-search-bar.png) ## Introducing Custom Events *June 12th, 2024* Based on user research and your feedback on segmentation, we've implemented *Custom Events*. Previously you could only use, capture, or track predefined events in Prepr which limited your options and didn’t always align with your segmentation needs. Now you can define custom events so you're completely free to set up and track the events you need. ![custom event](https://assets-site.prepr.io//4rskn2cggfe6-custom-event-triggered-by-customer.png) We've also streamlined the predefined events to the list below. - The `View` event is automatically sent to Prepr when a page load is detected by the Prepr tracking pixel. - The `Click` event is available for an upcoming feature to create metrics for A/B testing and personalization. - The `Like`, `Bookmark` and `Subscribe` events have built-in constraints. These events can only be recorded once per customer per content item. - The `SignUp` event is the only event not linked to a specific content item. This event prevents the customer from being automatically deleted after 90 days of inactivity. We trust that the custom events and predefined events cover all your needs to easily track visitors. For details on how to track and send events to Prepr, check out the [Events doc](/data-collection/recording-events#recording-custom-events). ## New GraphQL API version 2024-06-12 is available *June 12th, 2024* The GraphQL API has been updated for custom events and in preparation for upcoming features: - A new field `variant_key` to allow you to track impressions and clicks for Personalized and A/B tested components. This key supports the upcoming feature to provide metrics for A/B testing and personalization. - A new system field `_event` has been added to the schema. This field along with some other minor changes to the API support *Custom Events*. The new release also includes the following changes: - `ENUM` types can now be set to legacy mode and will be returned as a `STRING` (for existing Prepr environments). - Improved errors for incorrect requested locales. Check out the [GraphQL API upgrade guide](https://docs.prepr.io/graphql-api/upgrade-guide#version-2024-06-12) for more details. ## Content item list improvements *June 4th, 2024* Based on findings from our user research, we've implemented some improvements to the *Content items* list page that significantly enhance your experience with Prepr. Overall, we've updated the UI design of the *Content items* list page to make it more intuitive and less cluttered for content editors. As part of these UI updates, you'll notice that the checkboxes in the first column are visible when you hover over a content item. Click the checkbox to select content items to perform bulk actions like **Delete** or **Assign to**. This makes it easier for editors who need to perform actions on multiple items. ![select bulk actions](https://assets-site.prepr.io//4byzy0szg69o-select-bulk-actions.png) When the editor clears the selection with the new **Clear selection** button, the column names will become visible again. In this view you can see the intuitive sorting in the *Content item Title* and the *Modified date* column headers. Simply click the name of the column header or the arrows to toggle between ascending and descending order. Click the icon to choose other sorting options for *Publication date*, *Scheduled date* and the *Created on* date. You will also notice that we've made the sidebar collapsible to hide filters and avoid confusion. This means the editor can now focus on their core tasks, in other words, editing content items. ![sort with column headers](https://assets-site.prepr.io//1km832s5924x-sort-with-column-headers.png) Last, but not least, we've made the hover interactive for actions per content item when you need them. Instead of clicking, a simple hover over the content item makes the actions you need available, like the **Edit** or **Delete**. ![hover for content item actions](https://assets-site.prepr.io//4lw4xw69zcfv-hover-for-content-item-actions.png) While the actions and sorting capabilities have always been available, the new UI changes make the editing experience a lot more intuitive and user friendly. Check out the [Manage content docs](/content-management/managing-content/managing-content-items) for more details. If you have more suggestions on how we can simplify your experience with Prepr, we'd love to hear them! ## Content item workflow improvements *May 29th, 2024* Based on user research and your feedback, we've implemented some small improvements to content items that significantly enhance your experience with Prepr. The most obvious change is the introduction of additional publishing options. Instead of just **Publish and close**, you can now select **Publish and stay** or **Publish and add new**. This simplifies the process of publishing your work, then continuing with the same content item or immediately starting a new one. We've also added a convenient button at the top of a content item. This lets you cancel editing without having to scroll down to find the cancel button. ![publish content item](https://assets-site.prepr.io//76lb48x92yin-publish-a-content-item.png) Another improvement is the clear option to remove a schedule. While this was possible before, it wasn't very obvious. We've now added a link that allows you to easily remove the schedule. ![remove schedule](https://assets-site.prepr.io//6pn23s6jsrps-remove-schedule-from-a-scheduled-content-item.png) Finally, you no longer need to publish parent content items when a child item is changed. Previously, changing a linked item required you to re-publish the parent item, even if it wasn't altered. This led to unnecessary extra clicks. Now, you only need to publish the changed item and can immediately continue with other tasks. These updates have made working with Prepr even easier. If you have more suggestions on how we can simplify your experience with Prepr, we'd love to hear them! Check out the [Manage content docs](/content-management/managing-content/managing-content-items) for more details. ## Define your own fields for *Assets* *May 14th, 2024* We are very excited to bring you the long-awaited feature to add fields to Assets. It is now possible to define your own fields to keep track of asset-specific info like *Copyright* or *Source* in addition to the core asset fields for the title, description and the author. Now, it's also possible to enable localization for your assets. This means your editors can enter information about assets in the locale that is relevant for them. This feature gives you the flexibility to create your own Asset content structure with localization and makes it much easier for the front end to retrieve additional information about assets. This feature introduces a new **Asset** model available to any user who has access to the Prepr *Schema* or *Shared schema*. ![core asset fields](https://assets-site.prepr.io//3rjk713djj6i-the-asset-model-fields.png) When you enable localization on the **Asset** model, the fields in each asset will be available for all [available locales](/content-management/localizing-content). Check out the [Asset model doc](/content-modeling/defining-the-asset-model) for more details. ## Organize your models and components with Schema folders *May 10th, 2024* It's now possible to organize your models and components into folders. When you have dozens of models or components, these folders make it easier to find related models or related components instead of scanning a long alphabetical list. For example, when you have multiple components which are used as section of a page. ![Schema folder](https://assets-site.prepr.io//6tzv1o6ntdrm-create-new-folder-modal.png) ## Speed up text editing with new AI Generate and AI Optimize features *April 30th, 2024* We are very pleased to bring you two new features, *AI Generate* and *AI Optimize*. The *AI Generate* feature generates new text on request, for example, when a content editor wants to create a summary based on the main body text of an article. *AI Optimize* helps content editors to improve existing text, for example, to make their text longer, shorter or simpler. Both features make it quicker and easier for content editors to create more engaging text in their content. ![Generate and Improve example](https://assets-site.prepr.io//5fly5h44b6nw-generate-and-ai-optimize-text-example.png) Go to the **Schema** tab to set up the AI parameters for these features in the relevant *Text* fields. Check out the [*Text field* settings](/content-modeling/field-types#text-field) for more details. ## Use Frontify brand assets in Prepr content *April 9th, 2024* As requested, we've added a DAM integration to Prepr CMS to allow content editors to access Frontify brand assets in Prepr content. This integration gives you the benefit of ensuring that your assets are brand-compliant and allows you to maintain a single source for these assets. With this built-in integration, it's easy to set up a connection between Prepr CMS and your Frontify account. When your request for activation has been approved, you can activate the *Frontify* app in Prepr. Once done, content editors can include Frontify assets in their content items. ![embed images from frontify](https://assets-site.prepr.io//6qoqnvpicfd3-content-item-frontify-assets.png) For detailed instructions on integrating Frontify, please refer to the [Frontify integration guide](/integrations/frontify). ## New locales added for `fy-NL` and `es-MX` *March 26th, 2024* As requested, we've added support for the Frysk `fy-NL` and Mexican Spanish `es-MX` locales. Locales can be set up in the Organization **Settings** page. This feature is available to users who have the `Owner` role or a role with the *General* `Locales` setting enabled. For more details, check out the [localization doc](/content-management/localizing-content). ## Create cleaner schemas with Enumerations *March 26th, 2024* We are excited to bring you the long-awaited *Enumerations* feature. We've expanded the *Schema* so you can define your own enumerations and use them in any model or component with the *List* field. For example, when you want to define days of the week. Until now, you had to define list values every time you added a *List* field to a model or component. Now, you only need to create an enumeration once with a set list of values and reuse this list in multiple models or components. This means that you define a cleaner schema without duplicate list definitions. ![create enumeration](https://assets-site.prepr.io//2mjuanzs6950-create-enumeration.png) Check out the [enumerations doc](/content-modeling/managing-enumerations) for more details. The enumerations feature is available as from GraphQL API Version 2024-03-26. To activate and use enumerations, check out the [GraphQL API upgrade guide](/graphql-api/upgrade-guide). ## Sync your schemas with GitHub for a seamless CI/CD workflow *March 15th, 2024* We are happy to bring you a new feature, the **GitHub sync**. Until now you could only use the **Sync schema** feature to sync one schema to another, but it's not always ideal. The **GitHub sync** allows you to use standard GitHub functionality to sync schemas between environments. As a developer, this gives you more control over the sync process to manage schema updates exactly the way you need to. - You can sync both ways with the GitHub pull and push requests. - This sync not only adds items in the schema, but also removes unneeded items. You benefit from *version control* in GitHub, namely: - You can review the schema change history. - And you can revert changes. Check out the [Sync schemas doc](/development/working-with-cicd/syncing-a-schema#sync-schema-with-github) for more details on how to Sync your schemas with GitHub. ![push pull request](https://assets-site.prepr.io//s7lhw8vdwqh-push-pull-request.png) ## Keep track of user activities with the new Audit log *March 14th, 2024* With the new *Audit log* feature, it is now possible to keep track of user activities. The *Audit log* helps developers to troubleshoot errors or inconsistencies with the schema or content. The audit log is available at the organization level and you can filter logged activities by the **Date**, **Environment**, **User** and **Resource type**. The audit log shows you *Create*, *Update* and *Delete* actions on content items, models, components, remote sources, enumerations, webhooks, apps, users, assets, roles and segments. You can also track when a user publishes a content item and when a user executes a schema sync or GitHub push/pull sync. ![audit log](https://assets-site.prepr.io//4yuhq1ztdw2j-audit-log.png) Check out the [Audit log doc](/project-setup/audit-log) for more details. ## New Stage option available to create a Testing environment *March 14th, 2024* In our efforts to support the CI/CD process of your development team, you can now choose a **Testing** stage option when creating a new environment. This will help you adhere to best practices when managing your *Development*, *Testing*, *Acceptance* and *Production* Prepr environments. Check out [DTAP configuration options](/project-setup/setting-up-environments#set-up-a-dtap-configuration) for more details. ## Set the GraphQL API version in code *March 12th, 2024* When we make changes to the GraphQL API that aren't compatible with older versions, we release a new one with a specific date. By default, the API uses the default version associated with your access token. However, in response to customer feedback, you can now override this version using the 'Prepr-Version' header. For more information, refer to our [Versioning & Upgrade Guide](/graphql-api/upgrade-guide). ## More flexibility with new remote source features *March 4th, 2024* We bring you new remote source features in our ongoing endeavor to advance our existing functionality. The new features listed below give developers more control to manage remote sources more flexibly. - **Filters** Now you can enable filters for content editors to find remote items easier like in the example below. ![Add remote content to a content item](https://assets-site.prepr.io//7a0hjjkwwesq-choose-remote-items-with-filters.png) Check out [the custom remote source doc](/content-modeling/creating-a-custom-remote-source#step-1-set-up-your-custom-api-endpoint) for more details on how to set up an endpoint with filters. - **New remote source actions** Go to the remote source and click the icon to see the new remote source actions. ![remote source actions](https://assets-site.prepr.io//4eouo6z37p1a-remote-source-settings.png) - **Resync remote items** As a developer, you can now manually resync the items from a remote source. Prepr automatically resyncs remote source items when the `changed_on` date has been modified, but there are times when you need to resync the items on demand. This way, Prepr CMS is updated and the front end is up to date with current remote items. - **Activate** It is now possible to activate the remote source. This is useful when the API endpoint URL is no longer valid or the external source system is updated and no longer matches the endpoint definition. To resolve errors in these situations, the remote source will be deactivated until the issues are fixed. Once fixed, click **Activate** to reactivate the remote source. - **New remote source field settings** - **Set as Title** and **Set as Image** It is now possible to specify the `Title` and the `Image` when defining the fields in your remote source. Prepr uses these settings to display the Title and image for content editors to identify items from the remote source more easily. - **Make visible when searching for remote content** You can also choose which of the fields in the endpoint should be made `Visible` to the content editor. In the field settings, open the **Appearance** tab to enable or disable this setting. ![remote source field settings](https://assets-site.prepr.io//16b9mxuvck4c-remote-source-field-settings.png) ## Add Stack to the Dynamic Content field *February 28th, 2024* As you've requested, we released a new feature that allows you to add a *Stack* to the *Dynamic content* field. This new feature is an extension to the recently released [*Stack in component*](#create-better-content-structures-with-stack-in-a-component). It enables editors to create structured lists in articles that are created with the Dynamic Content field. For example, to add a list of recipes to an article about cooking equipment. Simply enable components in the list of content types in the *Dynamic content* field and choose the components that contain a *Stack* field. ![dynamic enable components](https://downloads-site.prepr.io/xvqqcyg5qpv-dynamic-content-field-settings-content-types-enable-components.png) By doing this, you allow the content editor to add a component with a *Stack* field in their dynamic content. For example, they can easily add things like a list of articles to their rich text like in the image below. ![dynamic content example](https://assets-site.prepr.io//1pgz85f4j2w6-dynamic-content-with-stack-in-component.png) ## Make the most out of components by including a date field *February 27th, 2024* We are pleased to announce that you can now include a date field in components. Enjoy this flexibility when modeling your content, for example, in an *Event* component where the event date is an integral part of this type of content. The date field in a component works the same way it does in a model, with the following options: - Single or multiple Date values - Single or multiple Date range values - Single or multiple Date time values - Single or multiple Date time range values - Business hours Check out the [Date field](/content-modeling/field-types#date-and-time-field) for details on how to set up this field. For developers who need to make API requests, the date field in a component is available as of GraphQL version 2024-01-31. ## More accessible content with 27 new Arabic locales *February 6th, 2024* As requested, we've expanded the range of locales with Arabic languages. We've included 27 new countries in the list of locales, such as Egypt `ar-EG` and Morocco `ar-MA`. If you have international partnerships and customers, make your content more accessible and marketable by publishing content in their local language. Check out our [localization docs](/content-management/localizing-content) to learn how to work with localization. ![Arabic locales](https://assets-site.prepr.io//2im17oj2h3fm-new-arabic-locales.png) If you need a specific locale that is not listed, please [contact our Support Team](https://prepr.io/support), and we will add it upon request. ## Create better content structures with Stack in a component *January 31st, 2024* The long awaited *Stack in a component* feature has been released. As a developer, you can now add a Stack field to components. This means that you can create more logical, flexible, and scalable content structures for your component-based pages. A typical example is when you need a row of buttons in a Call to action. To do this, create a *Button row* component and add a stack field to it to hold the buttons. You can then add the button row to any component you need like a *Call to action*. [Watch the video on how to use Stack in components.](https://youtu.be/SOdw6GM0wRA) ![add stack field to component](https://assets-site.prepr.io//7jyy1dp754l4-add-stack-to-component.png) ## Enjoy a renewed Dynamic Content Editor and Content Item detail page *January 25th, 2024* We are happy to enter the new year with this release which promises to deliver a multitude of benefits to you as a content editor: We implemented a new front-end framework in preparation for an upcoming release of the Live preview feature. You can now enjoy faster page loads with this update and a consistent layout when editing a content item with reference or stack fields. See below for an example of the renewed look and feel of the Personalization and A/B testing blocks in a **stack** field: ![updated personalization block](https://assets-site.prepr.io//3ywrut9o6r3i-home-page-with-personalization-updated-layout.png) This release also includes some reworked code resulting in faster loads and an improvement to the word counter and SEO information. The deprecated **Preview** button has also been removed, but check out [the content item preview doc](/project-setup/setting-up-previews) for details on how to set up your own preview URLs. A new *Dynamic Content Editor* has been implemented to give you a better user experience when editing lots of content at once. It's based on an established API that resolves some ongoing issues. You will notice clearer validations in the dynamic content fields, an improvement to the copy-paste function within content items and from external sources to content items, and the ability to use the Undo and Redo options. ![New content editor](https://downloads-site.prepr.io/52l78emlefvb-updatedcontenteditor.gif) ## Make the most out of your components with the location field *January 25th, 2023* We are pleased to announce that you can now include the location field in components. Enjoy this flexibility when modeling your content, for example, in an *Event* component where the event location is essential for this type of content. The location field in a component works the same way it does in a model. For developers who need to make API requests, the location field in a component is available as of [*GraphQL version 2023-11-02*](/graphql-api/upgrade-guide#version-2023-11-02). ## Gain more flexibility with new read/write options on your fields *January 25th, 2024* With the release of new read/write options, you have more control over how fields are used by content editors and developers. As requested, you can now set the following new options on a field: - Default - The field can be edited in the UI. - Read only - The field can’t be edited in the UI, but it can be edited through the API. - Hidden for non developers - The field is only visible for users with developer permissions. ![field appearance settings](https://assets-site.prepr.io//6yaq5nmykgss-field-appearance-settings.png) ## New Stack filter on content items *January 22nd, 2024* We are happy to bring you a new Stack field filter on content items in the GraphQL API and the Prepr UI. This feature makes it even easier to filter your content items. If you have content items with Stack fields that reference other content items, it is now possible to filter by these referenced content items. To add this filter in an API request, check out more details in [the reference docs](/graphql-api/fetching-filtering-collections#simple-reference--stack). ![filter with stack](https://assets-site.prepr.io//28gc6k2k383y-filters-with-stack.png) ## Prepr's UI is now up to eight times faster *January 16th, 2024* Prepr continually strives to enhance the reliability and performance of its applications. This is our primary focus, and we are always seeking ways to improve user and developer experiences. A recent update to our database queries has significantly improved the speed of our APIs and the UI. As a result, working with Prepr has become twice as fast since this past weekend. If you use the Mutation API, GraphQL API, and the Prepr UI in a development chain, you could experience time savings of up to eight times. If you have any feedback on the speed improvements, feel free to respond to feedback@prepr.io. Source: https://docs.prepr.io/stay-updated/changelog2024 --- # 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. ![shared schema](https://assets-site.prepr.io/2gn7v1d5qrsr//updated-navigation-shared-schema.png) 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. ![promote to group option](https://assets-site.prepr.io/5hftww3mvd8g//promote-to-shared-schema-example.png) 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. ![shared model example](https://assets-site.prepr.io/4u7oztg8t0am//shared-model-example.png) 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. ![Conditional visibility by environment toggle](https://assets-site.prepr.io/ey2e2n6oi4u//conditional-visibility-option-by-environment.png) 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**. ![shared content](https://assets-site.prepr.io/4uq8gnpj6lxf//updated-navigation-shared-content.png) Check out the [Create schema docs](/content-modeling) for more details. Source: https://docs.prepr.io/project-setup/architecture-scenarios/shared-content --- # 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-v2.vercel.app/en-US/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. ![Blog example - overview of posts](https://assets-site.prepr.io/x4436d9ejik//blog-example-pattern.png) ### 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. ![detailed post](https://assets-site.prepr.io/1tzt3qcw9irw//detailed-blog-page-example.png) 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: ![post-model](https://assets-site.prepr.io/5y4u2u6shbqo//post-model.png) |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. */} ![author-model](https://assets-site.prepr.io/38b9dp0fnj7a//author-model.png) |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. ![category-model](https://assets-site.prepr.io/7k6bw2yikczw//category-model.png) |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. ![SEO-component](https://assets-site.prepr.io/3sa84f3t2pi//seo-component.png) 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-v2.vercel.app/en-US) 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: ![example-home-page](https://assets-site.prepr.io/3hpgdizgjrgq//example-home-page-acme-lease-all-sections.png) 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: ![page-model-summary](https://assets-site.prepr.io/73d8z3vy53m3//page.png) 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. ![Hero component](https://assets-site.prepr.io/6qrza88iwlo6//hero-component-of-a-page.png) 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. ![Feature component](https://assets-site.prepr.io/7bmxboyh502y//feature-component.png) 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. ![CTA component](https://assets-site.prepr.io/19be2rmrvtgr//cta-component.png) 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. ![Static component example](https://assets-site.prepr.io/6eu9hi7pyczx//static-component.png) 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. ![Cards component](https://assets-site.prepr.io/2m5dxm4a1whd//cards-component.png) 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. ![FAQ model example](https://assets-site.prepr.io/3364zcul8wtz//faq-model.png) 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. ![Contact component example](https://assets-site.prepr.io/3gx8goreh9tx//contact-component.png) 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: ![navigation](https://assets-site.prepr.io//6r7wgnqxsa14-navigation.png) 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: ![navigation-model](https://assets-site.prepr.io//5fcnj5hbldip-navigation-model.jpg) 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. ![menu-item-model](https://assets-site.prepr.io//385cp4sa4pvd-menu-items.jpg) 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: ![app-config-model](https://assets-site.prepr.io//33nswh1c0iit-schema-for-demo-website-docs-and-model-templates-12.jpg) 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 --- # 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.* ![Next.js QSG end result](https://assets-site.prepr.io/uq1nuej0pj9//quick-start-guide-list-of-posts.png) ## 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. ![preview API URL](https://assets-site.prepr.io//35k5a4g45wuy-preview-access-token.png) 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. ![Example webhook - changed content](https://assets-site.prepr.io/7ibro5u053dl//revalidate-cache-webhook-changed-content.png) - Set the **URL** value to `{YOUR_DEPLOYMENT_URL}/api/post-updated`, choose `content-item.changed` for **Events** and choose `Post` for **Models**. ![Example webhook - published content](https://assets-site.prepr.io/2m8a63xejq2//revalidate-cache-webhook-published.png) - 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 --- # Nuxt Quick start guide *Estimated duration: 10 minutes* *This guide shows you how to connect Prepr to a Nuxt 3 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.* ![Nuxt QSG end result](https://assets-site.prepr.io/2x5l444ndgzb//nuxt-blog-post-list.png) ## 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 --- # 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.* ![Laravel Blog site end result](https://assets-site.prepr.io/2bf0iiz8knzz//laravel-blog-post-result.png) ## 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 --- # React Quick start guide *Estimated duration: 10 minutes* *This guide shows you how to connect Prepr to a React project to get data from Prepr CMS. You'll learn how to make a simple blog with React and Prepr CMS. By the end of this guide, you'll have a working app that looks like the image below.* ![blog site end result](https://assets-site.prepr.io//5oz8w28ybxje-screenshot-2023-05-10-at-111353.png) ## Prerequisites You need to have the following setup before you connect your React 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) ## Step 1: Create a new React project The instructions below will guide you on how to create an empty React project for your blog app. ### Install React You can skip this step if you have an existing React project. 1. Open a terminal and execute the command below to create a new React project called `prepr-react`. ```bash copy npx create-react-app prepr-react ``` 2. Now that the project is successfully created, go to the `prepr-react` folder, the root directory of the project, and start the project with the following commands in the terminal: ```bash copy cd prepr-react ``` ```bash copy npm start ``` 3. You should now be able to view your app on your localhost, for example, `http://localhost:3000/`. 4. Open your project with your preferred code editor. 5. Update `App.js` in the `src` folder with the following code to display your blog: ```js filename="./src/App.js" copy function App() { return (

My blog site

); } ``` You should now see something like the image below on your localhost. ![view component](https://assets-site.prepr.io//51xf6qxlzj71-screenshot-2023-05-10-at-102457.png) ## Step 2: Install Apollo Client Apollo Client is an integration tool that helps to retrieve CMS data with GraphQL. The instructions below show you how to install Apollo Client so that you can add GraphQL queries to request data from the Prepr API. 1. Stop the server you started in the above step (`CTRL-C`) and execute the following command in the terminal: ```bash copy npm install @apollo/client graphql ``` 2. Go to the `src` folder and create a `services` folder. Then, create a file called `apollo-client.js` in this folder. Copy the following code to this file to import and initialize Apollo Client: ```js filename="./src/services/apollo-client.js" copy const client = new ApolloClient({ uri: `https://graphql.prepr.io/${process.env.REACT_APP_PREPR_ACCESS_TOKEN}`, cache: new InMemoryCache(), }); ``` This client will be used to make API requests to endpoints provided by the Prepr CMS across your React application. 3. We recommend using environment variables to store sensitive information like access tokens. To add environment variables, create a `.env` file in the root directory of your project and add the access token like this: ```bash filename="./.env" copy REACT_APP_PREPR_ACCESS_TOKEN= ``` 4. Replace the placeholder value `` with an access token from Prepr. Get an access token by logging into your Prepr account: a. Click the icon and choose the **Access tokens** option to view all the access tokens. b. Copy the GraphQL Production access token to only retrieve published content items on your site. ![access token](https://assets-site.prepr.io//6jouln4xi3wp-default-access-tokens.png) 5. Update the `index.js` file in the `src` folder to add the `ApolloProvider` component with the following code: ```js filename="./src/index.js" copy {6-8,19-26} // Import the Apollo Provider and Apollo Client const root = ReactDOM.createRoot(document.getElementById('root')); const router = createBrowserRouter([ { path: "/", element: , }, ]); // Add the ApolloProvider root.render( ); ``` 6. Install the React Router DOM package to enable routing with the following command: ```bash copy npm install react-router-dom@6 ``` 7. Execute the following commands to make sure that Apollo Client is installed correctly: ```bash copy npm install npm start ``` If your app runs without errors, then the setup above was done correctly. The next step is to fetch content from Prepr using the installed Apollo client. ## Step 3: Fetch multiple articles Now that Apollo Client is installed and connected to Prepr, fetch the blog articles from Prepr. ### Add a GraphQL query 1. Go to the `src` folder, create a `queries` directory and create a file named `get-articles.js`. 2. Add the following query to this file to retrieve all articles: ```js filename="./src/queries/get-articles.js" copy query { Articles { items { _id _slug title } } } ` ``` If you’re using preloaded demo data in your Prepr CMS environment as mentioned above in the [Prerequisites](#prerequisites) section, you should have a few published articles as shown in the below image. The query will retrieve the *ID*, *Slug*, and *Title* of each article. ![demo articles](https://assets-site.prepr.io//4p8m8oymbtph-demo-articles.png) In the next step, we'll fetch and process the query response. ### Fetch data Now that the query has been added, fetch the articles from Prepr and display them in the app. 1. Open the `App.js` file in the `src` folder and replace the content with the code below to display the data retrieved from the query. ```js filename="./src/App.js" copy // Import the query and the apollo client function App() { // Execute the query const {loading, error, data} = useQuery(GetArticles); if (loading) return

Loading...

; if (error) return

Error :(

; // Set the query results const articles = data.Articles.items; return (

My blog site

    {articles.map((article) => ( // List the fetched articles
  • {article.title}
  • ))}
); } ``` Now when you view the website on your localhost, you'll see something like the image below. ![Local](https://assets-site.prepr.io//770picl832e3-screenshot-2023-05-10-at-105008.png) ## Step 4: Fetch individual articles Now that you have the list of articles, add links to them. When a visitor clicks on a link, your app should open a detailed article page automatically. The instructions below show you how to set up the routing from the main page to the detailed page and how to fetch the article details based on the slug of the article that was clicked. ### Add links 1. Update the `App.js` file to include a link tag on each article title as shown in the code below. ```js filename="./src/App.js" copy {5-6,22-23} // Import Link to enable links in the HTML function App() { const {loading, error, data} = useQuery(GetArticles); if (loading) return

Loading...

; if (error) return

Error :(

; const articles = data.Articles.items; return (

My blog site

    {articles.map((article) => (
  • {/* Add links to the article title */} {article.title}
  • ))}
); } ``` Now when you view the app, each article has its own link. When you click on the link, a new page opens with the slug in the URL, but a Page 404 error is displayed. Continue with the next step to fetch the article details and resolve this error. ### Fetch article details Add another query to fetch a specific article by its slug and make this page visible when clicking on an article. 1. Create a file called `get-article-by-slug.js` in the `queries` folder and add the following to query a specific article by its slug: ```js filename="./src/queries/get-article-by-slug.js" copy query ($slug: String) { Article (slug: $slug) { _id title content { __typename ... on Text { body text } ... on Assets { items { url } } } } }` ``` Now that the query is added, fetch the individual article by its slug. Fetch the article title and the article content. 2. Go to the `src` folder and create a new file called `ArticlePage.js` with the code below to fetch an article by its slug and display the article details. ```js filename="./src/ArticlePage.js" copy // Import the query and the apollo client // Get the slug from the URL const {slug} = useParams(); // Execute the query const {loading, error, data} = useQuery(GetArticleBySlug, { variables: {slug} }); if (loading) return

Loading...

; if (error) return

Error :(

; const article = data.Article; return ( <>

{ article.title }

{/* Loop through content types in article content */} {article.content.map((contentType) => { // Display image if it exists if (contentType.__typename === 'Assets' && contentType.items.length) { return (
{`Image
) } // Display text as HTML if (contentType.__typename === 'Text') { return (
) } })} ) } ``` 3. Finally, update the `index.js` in the `src` folder to include the route to the new article page with the following code: ```js filename="./src/index.js" copy {5-6,18-22} // Import the article page const root = ReactDOM.createRoot(document.getElementById('root')); const router = createBrowserRouter([ { path: "/", element: , }, // Add a route to the article page { path: "/:slug", element: , } ]); root.render( ); ``` Now, when you view your site, you can click on an article which will direct you to that specific article like in the image below. ![article detail](https://assets-site.prepr.io//507hx87v7wkw-screenshot-2023-05-11-at-162824.png) ## All done Congratulations! You have successfully connected a React 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 the React Tailwind module](https://tailwindcss.com/docs/guides/create-react-app) Source: https://docs.prepr.io/connecting-a-front-end-framework/react/react-quick-start-guide --- # 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.* ![Blog site end result](https://assets-site.prepr.io/6eqxbjrigrdt//vuejs-blog-posts-result.png) ## 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 --- # 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.* ![Blog site end result](https://assets-site.prepr.io/fp1a9v4zuar//angular-blog-post-site-end-result.png) ## 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 --- # 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.* ![Blog site end result](https://assets-site.prepr.io/4sptbzci3cja//gatbsy-blog-site-posts.png) ## 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 --- # 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.* ![blog site end result](https://assets-site.prepr.io/1h1i3di3fxkj//php-blog-site-post-list.png) ## 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 --- # 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.* ![Blog site end result](https://assets-site.prepr.io/5npbztnctwkt//astro-blog-post-list.png) ## 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 --- # 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.* ![Blog site end result](https://assets-site.prepr.io/74bgrcumcy41//svelte-blog-posts.png) ## 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 --- # Working with assets Follow these guidelines to power your digital content with images, videos, audios, and files. 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), [Gatsby](/connecting-a-front-end-framework/gatsby), [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), [Gatsby](/connecting-a-front-end-framework/gatsby), [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), [Gatsby](/connecting-a-front-end-framework/gatsby), [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), [Gatsby](/connecting-a-front-end-framework/gatsby) and [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. ![csr](https://assets-site.prepr.io//6yqki00jnsu9-csr.png) ## 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. ![ssr](https://assets-site.prepr.io//1ogtlzw4lc64-ssr.png) ## 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. ![ssg](https://assets-site.prepr.io//5ktab0u08oap-ssg.png) ## 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: ![isr](https://assets-site.prepr.io//7gcjsbh0l2pb-isr.png) ## 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 link, often known as the `source` - The new target URL, known as the `destination`. - An indicator (`boolean`) to specify if the redirect is `permanent`. 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 **Start from scratch**, **Next**, **Multi-item model** and **Next** again. 4. Enter *Redirect* as the *Name* and click **Save**. 5. Drag and drop the *Text* field type, from the list on the right into your model. a. Enter *Source* as the *Name*. b. Switch to the **Validation** tab and enable the **This field is required** toggle and the **This field must be unique** toggle. c. Click **Save**. 6. 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 model that has a slug field. c. Switch to the **Validation** tab and enable the **This field is required** toggle. d. Click **Save**. 7. Drag and drop the *Boolean* field type, from the list on the right into your model and enter *Permanent* as the *Name*, set a *Default value* of **True** and click **Save**. ![Redirect model](https://assets-site.prepr.io//25cpxcx8pnd-redirect-model.png) 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. Fill out the *Source* path 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 **Publish and close**. ![Example Redirect content item](https://assets-site.prepr.io//3bs5u5jnz1md-example-redirect-content-item.png) 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 `` to the API URL from a [Prepr access token](/graphql-api/authorization#access-tokens). 2) Use one of two methods to update the configuration file to handle the redirects. - **Redirect with Next.js**: Add the redirects from Prepr to the built-in `next.config.js` file. - **Redirect with Vercel**: Add the redirects from Prepr to the `vercel.json` file during build time so that Vercel processes them after deployment. That's it! Once you successfully build and deploy your project, the redirects are processed and can be tested by navigating to the outdated links. ## What's next? Check out our other best practice guides from the list below: - [Rendering strategies](/development/best-practices/csr-ssr-ssg) - [Using TypeScript with the GraphQL API](/development/best-practices/typescript) - [How to set up content item previews](/project-setup/setting-up-previews) Source: https://docs.prepr.io/development/best-practices/redirects --- # Handling SEO in a headless CMS *This article details how to solve SEO challenges when implementing a headless CMS.* ## Introduction SEO is the process of making a website easy to find through search engines like Google. So, setting up SEO measures is a necessary activity when implementing a front end. And this process has been made easier with the introduction of the CMS. Headless CMSs are becoming the more popular choice over traditional CMSs because of consistency across multiple platforms, flexibility, improved performance, and scalability. Despite these benefits, the very nature of a headless CMS that decouples the front end from the content means that there are some challenges when taking measures to improve SEO. ## SEO challenges with a headless CMS Traditional CMS platforms often come with built-in SEO tools that headless CMSs don't usually have. This means that developers need to implement an SEO strategy in the front-end application to deal with challenges when implementing a headless CMS. When you prepare an SEO strategy, consider the following topics: - Managing metadata - Setting up URLs - Managing redirects - Generating a sitemap - Reviewing content for SEO Let's look at each of these SEO topics in detail and how to handle them in Prepr CMS. ### Managing Metadata Metadata are elements like title and meta description with keywords that provide information about a webpage to search engines and web browsers. These elements are placed in the head HTML of a webpage and are used to help search engines understand the content and context of the page. Unlike headless CMSs, traditional CMSs usually include plugins that can customize and update meta tags for pages. So, some once-off development effort is needed to set these up dynamically in a headless CMS. #### How to manage metadata in a headless CMS Headless CMSs decouple content from the front-end presentation. Before implementing a headless CMS project, you will typically model the content first. During this stage you will model the SEO metadata. ![SEO component](https://assets-site.prepr.io//62nau9j7ep4d-seo-component.jpg) Important metadata include fields like the `Meta title` and `Meta description` like in the example above. For the purposes of sharing content on social media, you could also include a `Meta image`. You could even include a `priority` to indicate the pages that are most important for crawling and indexing. Use indicators like `nofollow` and `noindex` for content that should be ignored by searchbots. Use the guidelines below to set up the SEO metadata structure: - Keep the title tag short. Restrict the number of characters to 60. - Keep the metadata description to under 140 characters. - Use [robots metadata](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag-implementation) to tell search engines which pages to avoid and not index. By default, Googlebot will index a page and follow links to it. - Prevent content editors from using the same metadata description for multiple pages in your website - Include some help text on the SEO fields to guide content editors with the following tips: - Use a persuasive metadata description to get searchers to click your page. - Include keywords in your metadata description. - Set the metadata title tag to the H1 (title) of the page where it makes sense to do so. - Show intent in the metadata title tag. - Marketers should revise the title and meta description on pages based on the CTR for those pages. Once your structure is defined in the CMS, it's available to content editors and marketers to fill in values for fields like the title and the description. In the front end, it's then possible to retrieve the metadata to set the necessary tags for each page. #### How to set up metadata in Prepr CMS You can easily manage SEO metadata in Prepr CMS in a few steps. 1. Set up a template structure for the SEO metadata by creating an SEO component. ![SEO-component example](https://assets-site.prepr.io/1z8tvef3kukn//example-seo-component.png) 2. Include the SEO component in relevant models. These are the models that need to be rendered as pages in the front end. 3. The content editor can then store SEO metadata like the title, meta description, and set `Noindex` and `Nofollow` tags. 4. In the front end, include code that makes a [GraphQL API](/graphql-api) request to get the SEO metadata for the relevant page and map the values to their relevant HTML meta tags. Check out the [Google meta tags and attributes doc](https://developers.google.com/search/docs/crawling-indexing/special-tags) for attributes that are relevant to search engines. It's useful to know that many front-end frameworks abstract the creation of the meta tags and allow you to set meta tags dynamically. See the example code snippets below on how to set meta tags. ### Setting up URLs Search engines like Google use URLs as one of the factors for website ranking and to understand what the content of a page is about. SEO-friendly URLs improve indexing by search engines. Also, when visitors see a URL, they are more likely to click a URL they understand compared to a URL that has a bunch of numbers. Unlike headless CMSs, traditional CMSs include plugins that set URLs automatically. For instance, they offer built-in support for creating language-specific URLs, which is crucial for SEO. This can be easier to manage because the system automatically handles URL structures based on language settings. On the other hand, headless CMSs need custom development to manage URLs. You need to explicitly configure and maintain URL structures which is a more flexible solution but needs more technical input. #### How to set up URLs in a headless CMS Many headless CMSs allow editors to include a URL or slug for the page. The slug is the last part of the URL address that uniquely identifies a page. If possible, auto-generate this slug field value based on existing fields in the page content such as the page `name` or an article `headline`. The front end can then get this slug value to set up the URL for a page. ![slug-settings](https://assets-site.prepr.io/4qzvcxuezy52//slug-field-setup.png) To improve SEO, make sure that the generation of the slug follows the guidelines below. - Use short descriptive URLs that are easy to read like `example.com/best-practices/how-to-handle-SEO`. - Avoid complicated URLs with unrecognizable words or numbers like `example.com/products/page-id-1231/2019-09`. - Keep URLs constant. Search engines consider a new URL to be a link to a new page. If a URL changes for an existing page, the ranking of the page starts from scratch and it will take time for the page to regain its ranking in searches. - Use hyphens '-' in URLs and not underscores '\_' as separators. - Only use lowercase in URLs. - Use primary keywords in the URL, but don't repeat the keyword. Follow the guidelines below for SEO when setting up URLs in the front-end. - Organize your URLs into categories and sub-categories like `blog` or `best–practices` to improve content ranking. - Handle not-found pages and use [redirects](#managing-redirects). In the case of language-specific URLs, it's useful to note that many front-end frameworks include dynamic routing for internationalization. Check out the [Next.js docs](https://nextjs.org/docs/pages/building-your-application/routing/internationalization) for an example. ### Managing Redirects Redirects send visitors from a requested URL to another. You need redirects for pages that are broken or pages that were moved to ensure visitors and search engines access the most relevant or current page. Without the usual front-end management that you find in a traditional CMS, handling redirects can be more complex for a headless CMS. #### How to handle redirects in a headless CMS You can set up a simple content structure in the CMS to hold the original URL and the new URL for a page that needs to be redirected. In this structure, include an indicator field to define the redirect as `permanent` or `temporary`. ![Redirect model](https://assets-site.prepr.io/755unlorg9d7//example-redirect-model.png) Once the redirect structure is modeled, add a list of redirects to the CMS content. The front end can then query and send the redirect info to the deployment service. Check out the [Prepr Redirects guide](redirects) for example code snippets on how to handle redirects using Prepr CMS. ### Generating a sitemap A sitemap is a file that helps visitors and web crawlers navigate your website to discover and index pages. With a sitemap, you can ensure that search engines can discover your pages quickly and when a crawler finds a URL in your sitemap, it knows you want it in the search results. Traditional CMSs often include built-in support to generate a sitemap automatically. While headless CMSs don't include automatic sitemap generation for search engine crawling. Additional development effort is therefore needed for a headless setup. #### How to generate a sitemap in a headless CMS The sitemap structure should follow the guidelines below: - The XML sitemap format provides additional information about images, video, and localized versions of your pages. - The sitemap should include fully-qualified, absolute URLs. - The `` tag must be consistently updated to indicate when the content last changed. A sitemap for a project contains a list of all the pages that it wants the search engine to find like in the example below. ```xml filename="sitemap.xml" copy https://www.xmlsitemapgenerator.org/en/ 2005-01-01 monthly 0.8 ``` Headless CMSs allow you to include URL or slug info for each content page. The front end application can then retrieve this info for each page and compile the sitemap structure dynamically during deployment. #### Generate a sitemap dynamically from Prepr CMS You can make use of the available page content in Prepr CMS to generate the sitemap with the steps below. 1. Make the `base URL` available in an environment variable. 2. Query the slugs for each of your page content items. 3. Loop through these items and assign them to an array. 4. For each page in the array, set the URL in the sitemap to the `base URL` + `slug` and set the `lastmod` value to the system date field `_changed_on` of the content item. See the simple Next.js code snippet example below that automatically generates a sitemap from Prepr CMS during the build of the web app. ```js filename="sitemap.js" copy let pages = [] const { data } = await client.query({ query: gql` query { Pages { items { _slug _changed_on } } } `, }) data.Pages.items.map((page) => { pages.push({ url: process.env.SITE_URL + '/' + page._slug, lastModified: new Date(page._changed_on), changeFrequency: 'monthly', priority: 1.0, }) }) return pages } ``` ### Reviewing Content for SEO Search engines prioritize fresh and relevant content, so outdated content loses visibility in search engine results. This leads to a decline in organic traffic and a diminished online presence. When using a headless CMS, you can easily publish content updates to the front end whenever the changes are needed. However, a headless CMS usually lacks a WYSIWYG editor and SEO plugins to measure content performance. This makes it difficult to preview how content changes will look and perform before the front end goes live. #### How to review content in headless CMSs Most CMSs do not include tools to review the content for SEO impact. In these cases, you need separate monitoring software to review the content for SEO performance in search engines. #### How to review content in Prepr CMS Prepr CMS includes an [automatic SEO review feature](/content-management/managing-content/optimizing-content-for-seo) and the ability to include a [front end preview](/project-setup/setting-up-visual-editing) for each piece of content. For more advanced SEO performance criteria, consider a dedicated marketing monitoring tool or SEO website crawler software. ## Schedule a free consultation Do you still have questions on SEO 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/seo --- # Using TypeScript with the GraphQL API *This article explains how to make the most out of Prepr GraphQL API features when using TypeScript in your front-end app.* ## Introduction TypeScript is a strongly typed programming language that builds on JavaScript. Developers choose to use TypeScript instead of JavaScript in their projects to take advantage of cleaner and more scalable code, better code readability, type safety, and code that's easier to debug and test. By using TypeScript in *Strict Mode*, you get stronger guarantees of program correctness for types and null checks. You can use a GraphQL code generator to generate TypeScript types and keep these up to date with any schema changes. Prepr delivers strict types in the GraphQL API schema so that TypeScript in [strict mode](https://www.typescriptlang.org/tsconfig#strict) can support the following situations in the front end: - To process content fields in their expected data types. - To make sure that some fields in content items are not null before rendering the content in the front end. ## Enable strict mode and generate TypeScript types Follow the steps below to use the strict mode feature in Prepr CMS, generate TypeScript in your front end and process an API response with strong TypeScript types. Let's start with the setup in your Prepr environment. And that's it! You've successfully implemented TypeScript strict mode in your front-end. If you found this article useful and would like to explore other similar topics in the Prepr docs, [please let us know](mailto:feedback@prepr.io). Source: https://docs.prepr.io/development/best-practices/typescript --- # Using webhooks Webhooks in Prepr CMS let you receive real-time updates for any events. Whenever a content item, asset, segment, customer, schema or tag changes, Prepr sends a secure HTTP `POST` request to your webhook endpoint. This allows your application to respond to an event in Prepr — whether that's syncing data, triggering notification or other automation, or keeping your UI in sync with content changes. ## Event types The events below can be used to trigger a webhook notification. Depending on your plan some options may not be available. ### Content items - `content_item.published` - `content_item.unpublished` - `content_item.created` - `content_item.changed` - `content_item.deleted` ### Assets - `asset.created` - `asset.uploaded` - `asset.changed` - `asset.deleted` - `storage_file.deleted` - `cdn_file.deleted` ### Schema - `schema.changed` ### Segments - `segment.created` - `segment.changed` - `segment.deleted` ### Customers - `person.created` - `person.changed` - `person.deleted` - `person.segment.added` - `person.segment.removed` ### Tags - `tag.created` - `tag.changed` - `tag.deleted` ## Event structure The table below outlines the structure of the webhook request, detailing key parameters and their associated data. Each parameter represents an aspect of the event, including metadata. | Field name | Field type | Description | |-------------------------|------------|----------------------------------------------------------| | `id` | string | The event unique identifier. | | `created_on` | string | The timestamp in UTC when the event is created. | | `event` | string | The triggered event, for example `content-item.published`.| | `payload` | object | Object with info about the resource that triggered the event.| | `performed_by` | string | The Prepr user who triggered the event.| The sections below describe the payload for each resource in more detail. ### Content items The below example request is the payload object when a `content-item.published` event triggers for a `Post` model. ```json copy { "id": "75ec2d8c-e5ba-452e-be08-3524af2e1f49", "created_on": "2025-03-19T14:30:49+00:00", "changed_on": "2025-05-28T09:01:45+00:00", "label": "Publication", "read_time": { "en-US": 2, "nl-NL": 2 }, "publish_on": { "en-US": "2025-05-28T09:01:00+00:00", "nl-NL": "2025-02-19T12:33:00+00:00" }, "slug": { "nl-NL": "de-top-5-mythes-over-autoleasing-ontkracht", "en-US": "the-top-5-myths-about-car-leasing-debunked" }, "model": { "id": "4a8b8f49-b5cd-412f-97e0-5b04a072688d", "body_singular": "Post", "body_plural": "Posts" } } ``` | Field name | Field type | Description | |-------------------------|------------|----------------------------------------------------------| | `id` | string | The content item unique identifier. | | `created_on` | string | The timestamp in UTC when the item is created. | | `changed_on` | string | The timestamp in UTC when the item is changed. | | `label` | string | Type of resource. For content items, this value is `Publication`.| | `read-time.{locale}` |integer| Values are listed for each locale, for example `en-US`. The calculated time a user reads an article in minutes.| | `publish_on.{locale}` |string |Values are listed for each locale, for example `en-US`. The timestamp in UTC when the item is published. | | `slug.{locale}` |string|Values are listed for each locale, for example `en-US`. The slug value of the content item, if applicable.| | `model.id` |string|The internal id of the model.| | `model.body_singular` |string|The singular name of the model, for example `Post`.| | `model.body_plural` |string|The plural name of the model, for example `Posts`.| ### Assets The below example request is the payload for an `asset.changed` event. ```json copy { "id": "c8580913-bbac-4309-9f74-95a6835930b8", "created_on": "2025-03-19T16:01:14+00:00", "changed_on": "2025-05-27T15:23:33+00:00", "label": "Photo", "name": "bmw", "body": "", "author": "", "status": null, "replaceable": true, "reference_id": "b773b7b3-97ce-40c3-ae1f-b1369d0516e1", "reference": null, "original_name": "img", "mime_type": "image/png", "extension": "png", "height": 250, "width": 496 } ``` | Field name | Field type | Description | |-------------------------|------------|----------------------------------------------------------| | `id` | string | The asset unique identifier. | | `created_on` | string | The timestamp in UTC when the asset is created. | | `changed_on` | string | The timestamp in UTC when the asset is changed. | | `label` | string | Type of resource. For assets, this value is `Photo`, `Video` or `Document`.| | `name` | string | The name of the asset. | | `body` | string | Additional information about the asset. | | `author` | string | The person who created the asset such as the photographer.| | `reference_id` | string | The external id of the asset. | ### Schema The schema events currently don't contain any payload. ### Segments The below example request is the payload for a `segments.deleted` event. ```json copy { "id": "sgm_5g4820qaz70", "created_on": "2025-05-28T08:52:19+00:00", "changed_on": "2025-05-28T08:52:19+00:00", "synced_on": "2025-05-28T08:52:19+00:00", "label": "Segment", "body": "New segment", "description": null, "reference_id": "new-segment", "query": { "conditions": [ { "type": "event", "event_name": "View", "result": true } ] }, "mode": 2, "count": null } ``` | Field name | Field type | Description | |-----------------------|------------|----------------------------------------------------------| | `id` | string | The segment unique identifier. | | `created_on` | string | The timestamp in UTC when the segment is created. | | `changed_on` | string | The timestamp in UTC when the segment is changed. | | `label` | string | Type of resource. For segments, this value is `Segment`.| |`body` | string | The name of the segment as it's displayed in the CMS.| |`reference_id` |string | An external id for the segment. This value can be used to identify the segment in an external CRM system, if applicable.| |`query.conditions` |array | A list of condition objects for this segment. The object fields depend on the condition options saved for this segment. For a complete list, check out the [segments doc](/personalization/managing-segments).| ### Customers The below example request is the payload for a `person.changed` event. ```json copy { "id": "3b0e2f5e-5b06-4563-828d-13ce49252672", "created_on": "2024-08-23T07:20:45+00:00", "changed_on": "2025-05-27T15:48:20+00:00", "last_seen": "2024-08-23T07:20:45+00:00", "label": "Person", "reference_id": null, "first_name": "Braylen", "last_name": "Nash", "full_name": "Braylen Nash" } ``` | Field name | Field type | Description | |--------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `id` | string | The customer unique identifier. | | `created_on` | string | The timestamp in UTC when the customer is created. | | `changed_on` | string | The timestamp in UTC when the customer is changed. | | `label` | string | Type of resource. For customers, this value is `Person`. | | `full-name` | string | The full name of the customer. For a full list of available customer characteristics, checkout the [customers doc](/data-collection/managing-customer-data-manually#updating-customer-profiles). | ### Tags The below example request is the payload for a `tag.created` event. ```json copy { "id": "c921ef1e-b8e5-4e8a-8cfa-2914665c3bf1", "created_on": "2025-09-03T12:40:49+00:00", "changed_on": "2025-09-03T12:40:49+00:00", "label": "Tag", "color": null, "body": "subscriber", "slug": "subscriber" } ``` | Field name | Field type | Description | |--------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `id` | string | The customer unique identifier. | | `created_on` | string | The timestamp in UTC when the tag is created. | | `changed_on` | string | The timestamp in UTC when the tag is changed. | | `label` | string | Type of resource. For tags, this value is `Tag`. | | `body` | string | The value of the tag. | ## Creating a webhook Webhooks in Prepr send notifications as `POST` requests and include a `JSON` payload with Prepr headers and custom headers, if defined in the webhook. Follow the steps below to add a new webhook. 1. Log in to your Prepr account with a user that has *Owner*, *Admin* or *Developer* rights. 2. Click the icon and choose the **Webhooks** option. 3. Create a new webhook by clicking the **Add webhook** button. 4. Add the URL of the endpoint where the notifications will be sent. ![Example webhook](https://assets-site.prepr.io/2m8a63xejq2//revalidate-cache-webhook-published.png) 5. Select the [events](#event-types) that will trigger the request. ![Example webhook - choose event](https://assets-site.prepr.io/2e718vvajpr//webhook-example-choose-event-to-trigger-webhook.png) 6. Click the **Save and close** button. Check out the list below for additional info you can include in your webhook. ### Models When you select a content item event, you will receive notifications when any content item is created, published, unpublished, changed, or deleted. You can further specify which content items you want to receive notifications from. Select one or more models to receive webhook events for content items of that specific model. ![Filter events by model](https://assets-site.prepr.io/7dwh2jcfr2l//webhook-example-choose-model-for-trigger.png) ### Custom headers There are some use cases where an application requires some fields to be added in the header of the webhook payload. For example, for access tokens or a personal scope key. To add a custom header, enter a header key and value. ![Add custom headers](https://assets-site.prepr.io/4qcmt4tatjrr//webhook-example-headers.png) ## Response View the full list of notifications sent to your webhook on the *Webhook detail* page in your Prepr account. From here you can view the response the Prepr server received from your endpoint. ![Webhook response](https://downloads-site.prepr.io/2ldsph3ah1vf-webhook-response.gif) Your endpoint should return a `2xx` HTTPS response for all notifications. When other status codes are returned the notification is considered failed and will be retried. If your webhook continues to fail multiple times in 24 hours, your webhook will be disabled. The account owner and any [*Technical contact*](/project-setup/managing-roles-and-permissions#technical-contact) users will be notified in this case. ## Retry behavior Prepr attempts multiple times to deliver a given notification to your webhook endpoint with an exponential back off. You can configure a maximum number of retries. If your endpoint has been disabled you can still expect to see future retry attempts. ## Disable behaviour Prepr will actively notify the account owner and any [*Technical contact*](/project-setup/managing-roles-and-permissions#technical-contact) users when the webhook is misconfigured or the error rate is 100%. The email also states when the endpoint will be automatically disabled. ## View attempts To manage an existing webhook, go to **Settings → Webhooks** and click the specific webhook in the list. All attempts of this webhook of the last three days can be viewed and retried here. You can also view the response the Prepr server received from your endpoint. ## Resend webhooks You can resend a webhook event by clicking the icon. ## Disable webhooks You can easily switch off your webhook temporarily. Go to **Settings → Webhooks** and click the specific webhook in the list. Switch it off by disabling the **Active** toggle. ## Performance considerations Respond to all webhook events in 12 seconds or less. After 12 seconds the notification is considered failed and will be retried. ## Security guidelines We recommend you protect the endpoints configured in each webhook. This prevents unauthorized actions on your app. ### Authorization headers When configuring your webhook in Prepr, add an authorization *Header* with a secret access token only your incoming webhook server knows. Prepr will send all of the custom headers you added when sending a notification, including authorization. If the values don't match, you can ignore the request. ### Whitelisting Prepr server IPs You can ensure your app is always communicating with Prepr through one of our IP addresses. ```http copy 87.233.165.0/26 2001:9a8:0:4b:: 64 bits ``` ### Webhook signatures Prepr will sign the webhook events it sends to your endpoints. We do so by including a signature in each event’s `Prepr-Signature` header. This allows you to validate that the events were sent by Prepr, not by a third party. Before you can verify signatures, you need to store your endpoint’s ID when creating a new Webhook. Each ID is unique to the endpoint to which it corresponds. If you use multiple endpoints, you must obtain an ID for each one. **Verifying signatures**\ The `Prepr-Signature` header contains the full json payload you receive. Prepr generates signatures using a hash-based message authentication code (HMAC) with SHA-256. Compute an `HMAC` with the `SHA256` hash function. Use the endpoint’s signing ID as the key, and use the json payload string as the message. Compare the signature in the header to the expected signature. If a signature matches, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance. To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures. ### Preventing replay attacks A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, Prepr includes a timestamp in the `Prepr-Signature` header. Because this timestamp is part of the signed payload, it is also verified by the signature, so an attacker cannot change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload. We recommend a tolerance of five minutes between the timestamp and the current time. We advise that you use Network Time Protocol (NTP) to ensure that your server’s clock is accurate and synchronizes with the time on Prepr servers. Prepr generates the timestamp and signature each time we send an event to your endpoint. If Prepr retries an event, for example: your endpoint previously replied with a non-2xx status code, then we generate a new signature and timestamp for the next delivery attempt. Source: https://docs.prepr.io/development/best-practices/webhooks --- # LLM-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:** https://docs.prepr.io/llms.txt **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:** https://docs.prepr.io/llms-full.txt **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:** https://docs.prepr.io/graphql-api.md **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/development/best-practices/llm-friendly-docs --- # Environment-to-environment content export *This article explains how to export content from one environment to another, for example, when you want to do system testing in your development environment with realistic content from the production environment.* ## Prerequisites Make sure that the **Allow Developer actions** and **Allow bulk update content items and assets** permissions are enabled for users who need to export content. The **Export to** action is available in the Content items list page for [*Developer*](/project-setup/managing-roles-and-permissions#developer) users only. ## Export content from one environment to another The process below shows you how to export content from one environment to another in the same organization. Source: https://docs.prepr.io/development/working-with-cicd/syncing-content --- # Sync schemas between two environments *This guide shows you how to update one schema with the other, for example, when you have a development and production environment with the same schema that is out of sync.* ## Introduction In the event that you have separate environments, for example, *Development*, *Testing*, *Acceptance*, and *Production*, you may need to sync the schemas in these environments. You can do this automatically by running a schema sync in Prepr. ![Schema sync modal](https://assets-site.prepr.io/3ryyxw6uwaf8//schema-page-sync-schema-action.png) There are a few schema sync processes you can choose from: - [*Direct schema sync*](#direct-schema-sync) - Use this process to directly compare and sync your schema between two environments in the same organization. - [*GitHub schema sync*](#github-schema-sync) - Export to a GitHub repository or import from a GitHub repository to keep your schema in sync between environments. - [*GitLab schema sync*](#gitlab-schema-sync) - Export to a GitLab project or import from a GitLab project to keep your schema in sync between environments. - [*Bitbucket schema sync*](#bitbucket-schema-sync) - Export to a Bitbucket repository or import from a Bitbucket repository to keep your schema in sync between environments. - [*Azure DevOps schema sync*](#azure-devops-schema-sync) - Export to a Azure DevOps repository or import from a Azure DevOps repository to keep your schema in sync between environments. ## Use cases See the following use cases for when you may need to synchronize your schema: - **Sync production to development** An example *DTAP strategy* is to maintain the schema in the *Production* environment and when the same content structure is needed for realistic test cases this schema needs to be copied to the *Development*, *Test*, or *Acceptance* environment. Learn more on [how to set up a DTAP configuration](/project-setup/setting-up-environments#set-up-a-dtap-configuration). - **Sync development to production** After testing your development on the latest schema version in the *Development* or *Test* environments, it's possible that you may need to make changes to the live schema. In this case, you could copy these changes to the *Production* environment. - **Share a schema between environments** Use the *Shared schema* feature to maintain one schema across multiple environments, for example, for multiple brands. Check out more details in the [environments doc](/project-setup/setting-up-environments#environment-setup-for-multiple-brands). A schared schema can also be imported from GitHub or GitLab or exported to GitHub or GitLab. This could be useful for agencies when you want to do testing with client's shared schema in your own organization instead of in the client organization. ## Prerequisites You need to have a role, such as the *Developer* or *Admin* role, with the **Schema** permission enabled to have access to the **Sync schema** action. If you need to sync a shared schema, then you need the Organization \**Schema* permission enabled. Check out [roles and permissions in Prepr](/project-setup/managing-roles-and-permissions#add-or-edit-roles) for more details. ## Direct schema sync Use the direct schema sync process if you choose not to use an external service like [*GitHub sync*](#github-schema-sync), [*GitLab sync*](#gitlab-schema-sync), [*Bitbucket sync*](#bitbucket-schema-sync), or [*Azure DevOps*](#azure-devops-schema-sync). The direct schema sync needs no external tools, whereas using an external service gives you more flexibility and the added benefit of version control. Note the list of constraints below before triggering the direct schema sync process. ### Constraints - This process only works between environments in the same organization. - Models in your target environment will be overwritten with the models from the current environment if their *Singular names* match. Fields will be added or deleted to match the updated structure. * Components, enumerations and remote sources in your target environment will be overwritten with the components, enumerations and remote sources from the current environment if their *Type name* values match. Fields will be added or deleted to match the updated structure. - Models, components, enumerations or remote sources that are not in the current environment, but present in the target environment will be deleted if they are unused. The process below shows you how to sync your schema from one environment (*current environment*) to another (*target environment*). ## GitHub schema sync The process below shows you how to connect to your GitHub account and sync a schema using a GitHub repository. ## GitLab schema sync The process below shows you how to connect to your GitLab account and sync a schema using a GitLab repository. ## Bitbucket schema sync The process below shows you how to connect to your Bitbucket account and sync a schema using a Bitbucket cloud repository. ## Azure DevOps schema sync The process below shows you how to connect to your Azure DevOps account and sync a schema using an Azure DevOps repository. If you have any questions about schema synchronization, please [reach out to our Support team](https://prepr.io/support). Source: https://docs.prepr.io/development/working-with-cicd/syncing-a-schema --- # Manually exporting and importing a schema *This guide shows you how to manually export and import parts of a schema, namely, models, components, enumerations and remote sources.* ## Introduction In the event that you have separate environments and you want to copy parts of the schema from one environment to another, you can export and import the parts you need, namely, [a model](#export-and-import-a-model), [a component](#export-and-import-a-component), [an enumeration](#export-and-import-an-enumeration), or [a remote source](#export-and-import-a-remote-source). ## Export and import a model Use the export and import if you only need a couple of models copied from one environment to another. For example, export a model from your staging environment and import the model into your production environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same models across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click a model from the list of models on the left. 3. Click the button at the top of the model. 4. Click **Export model** to download a JSON file of the model. ![export-model](https://downloads-site.prepr.io/i7b2iwb48nr-export-model.gif) To import a model, follow these steps: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Then, click the **+ Add model** button. 3. Click **Or import a model**. 4. Choose the JSON file of the model that you want to import. When you import a model, the settings are also copied across. ![import-model](https://downloads-site.prepr.io/42d2oussyg6m-import-model.gif) ## Export and import a component Use the export and import if you only need a couple of components copied from one environment to another. For example, export a component from your staging environment and import the component into your production environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same components across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export a component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click the component that you want to export from the list of components on the left. 3. Click the button at the top of the component. 4. Click **Export component** to download a JSON file of the component. ![export-component](https://downloads-site.prepr.io/6ckxk6ka60w2-export-a-component.gif) To import a component, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add component** button. 3. Click **Or import a component**. 4. Choose the JSON file of the component that you want to import. ![import-component](https://downloads-site.prepr.io/2o4wga7ya4pr-import-a-component.gif) ## Export and import an enumeration Use the export and import if you only need a couple of enumerations copied from one environment to another. For example, export an enumeration from your production environment and import it into your development environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same enumerations across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export an enumeration, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click the enumeration that you want to export from the list of enumerations on the left. 3. Click the button at the top of the enumeration. 4. Click the **Export enumeration** option to download a JSON file of the enumeration. ![export enumeration](https://assets-site.prepr.io//6mk9yi50hg1o-export-enumeration.png) When the export is successful, you'll find the JSON file in the location you selected. To import an enumeration, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add enumeration** button. 3. Click the **Import enumeration** link. 4. Choose the JSON file of the enumeration that you want to import. ![import enumeration](https://assets-site.prepr.io//5skbn5qa64nb-import-enumeration.png) When the import is successful, you'll see the detailed enumeration in your schema. ## Export and import a remote source Use the export and import if you only need a couple of remote sources copied from one environment to another. For example, export a remote source from your production environment and import it into your development environment. To sync a schema with models, components, enumerations and remote sources from another environment then follow the process detailed in the [Sync schema doc](/development/working-with-cicd/syncing-a-schema) instead. To share the same remote sources across multiple environments, for example when an organization has different brands, but needs content in separate environments, you can create a shared schema as detailed in the [Shared schemas doc](/project-setup/architecture-scenarios/shared-schema). To export a remote source, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Click the remote source that you want to export from the list of remote sources on the left. 3. Click the button at the top of the remote source. 4. Click the **Export remote source** option to download a JSON file of the remote source. ![export custom source](https://assets-site.prepr.io//6231p0s82264-export-custom-source.png) When the export is successful, you'll find the JSON file in the location you selected. To import a remote source, follow these steps: 1. Click the **Schema** tab to open the **Schema Editor**. 2. Then, click the **+ Add remote source** button. 3. Click the **Import custom source** link. 4. Choose the JSON file of the remote source that you want to import. When the import is successful, you'll see the detailed remote source in your schema. If you have any questions about exporting and importing parts of your schema, please [reach out to our Support team](https://prepr.io/support). Source: https://docs.prepr.io/development/working-with-cicd/exporting-and-importing-a-schema --- # Managing content items *Easily manage your content items by using some basic features in Prepr.* ## Introduction This article shows you how to perform the following core tasks to manage your content: - [Create a content item](#create-a-content-item) - [Publish a content item](#publish-a-content-item) - [Manage versions](#manage-versions) - [Delete a content item](#delete-a-content-item) - [Find your content items](#find-your-content-items) ## Create a content item To add a new content item: 1. Go to the **Content** tab. Here you'll find a list of all content items in your Prepr environment. 2. Click the **Add item** button. The availability of models depends on the user role and permissions you have. ![Add item button](https://assets-site.prepr.io/4yfqdex5itot//create-a-content-item.png) 3. Select a model. Now the content item is created and you can start composing your content. ![content item created](https://assets-site.prepr.io/2a4g82dala6g//add-new-item.png) The shown fields depend on the [model settings](/content-modeling/managing-models) in the *Schema*. The fields marked with an `*` are required. ### Guidance and help text Depending on the setup of each field, you might see some help text for additional information about the content you need to create. ![help text example](https://assets-site.prepr.io/4y0js1w87s3z//content-item-detail-help-text.png) You might also see some additional highlighted guidance. Check out the [*Help text* field](/content-modeling/field-types#help-text-field) for setup details. ![help text field examples](https://assets-site.prepr.io/47jck81o22wq//content-with-info-box.png) You can also create language variants of your content item in a multi-lingual setup. Check out the [Localization doc](/content-management/localizing-content#create-a-language-variant) for more details. ### Use AI to generate text The *AI Generate* feature generates new text on request, for example, when you want to create an SEO title based on the main title of an article. ![AI Generate example gif](https://downloads-site.prepr.io/5tfuawuiil7u-auto-generate-text-with-ai.gif) This feature makes it quicker and easier for you to create engaging text. For setup details, check out the [field settings](/content-modeling/field-types#ai-generate). ### Use AI to optimize text The *AI Optimize* feature helps you to quickly improve existing text, for example, to make text longer, shorter or simpler. ![AI Optimize example gif](https://downloads-site.prepr.io/zcquh1k1lie-optimize-text-with-ai.gif) This feature helps you quickly improve the quality of the content you publish. For setup details, check out the [field settings](/content-modeling/field-types#ai-optimize). ## Publish a content item When you're happy with the content item that you created and want it to be used and displayed in the web app, all you need to do is publish the content item. ![publish content item](https://assets-site.prepr.io/37m54jshl99k//content-item-detail-publish-actions.png) You can publish a content item directly by clicking the **Publish** button or selecting one of the other publish options in the dropdown list, or by using shortcut keys to publish the content item. If your content item has any unpublished child content items, either content references or in a stack field, you need to choose to either publish all content items including the unpublished child items or only the parent content item. ![publish nested items example](https://downloads-site.prepr.io/4ooirmjcsywc-publish-nested-items.gif) When you publish the content item directly, the *Workflow stage* of the content item is automatically changed to *Done*. Check out the [Collaboration and workflows doc](/content-management/collaboration) for more details on workflow stages. If you want to make changes to a published content item, edit the content item and click the icon to save the changes without publishing them. This means there'll be two versions; your saved version and the published version. You can then publish the saved version of the content item after making your changes. ## Schedule a content item When you want content item changes to be published in the future, you can schedule a content item. To schedule a content item, simply click to open the **Publish** actions list and click the **Schedule** option. ![schedule a content item](https://assets-site.prepr.io/5a1t6pmufl39//content-item-detail-schedule.png) Then select the date and time for when you want the content item to be published by the web app. The content item will be marked as *Scheduled* until the date and time that you selected. You can update the scheduled content item any time before the scheduled date and time without needing to reschedule the content item. Check out the [Calendar view](#calendar) to get a clear overview of scheduled items. To reschedule a content item in the calendar view, you can simply drag and drop the item to the desired date or click the icon and choose the **Reschedule** option. ![Reschedule in calendar view](https://downloads-site.prepr.io/2uzygwj82bep-reschedule-items.gif) Alternatively, you can click the **Reschedule** option in the content item when it's already published or scheduled. When you reschedule a published content item, the *First Published at* date and time is set to the new date and time you choose. ![rescheduling](https://downloads-site.prepr.io/1t3kx6wxot2y-rescheduling.gif) This means you can order the content items in the front end when they're ordered by the *First Published at* date and time. When you choose to schedule a content item, you can also enter the *Unpublish on* date and time for temporary content. When this date and time is reached the content item will be *Archived* and no longer available to the web app. You can see all scheduled content items in the *List view* by filtering on the **Publication status** or the *Kanban view* by viewing the **Done** column for *Scheduled* items. You can remove a schedule from a scheduled content item by opening the **Publish** dropdown list and choosing the **Remove schedule** option. When you remove the schedule the workflow stage of the content item is set to *In progress*. ![remove schedule](https://assets-site.prepr.io/6s1g885ck2wh//content-item-detail-remove-schedule.png) ## Preview content items You have a couple of options to preview content items to check what your content changes look like in the web app directly from Prepr. ### Visual Editing You can click the icon to open Visual Editing. Visual Editing is a live preview of a content item in a side-by-side view. Simply save the content item to see your content changes instantly in this view. ![Visual editing icon](https://assets-site.prepr.io/4den54jvykwf//content-item-detail-page-highlight-visual-editing-icon.png) When editing content in this live preview mode, you'll notice the following additional options: - You can choose different screen sizes to get an accurate view of the page on different devices. ![Visual editing - screen sizes](https://assets-site.prepr.io/2wynl6zv6k8//content-item-detail-page-highlight-screen-sizes.png) - When multiple URLs are enabled for Visual editing, for example, for test and development environments, you can switch to a different environment. ![Visual editing - choose URL](https://assets-site.prepr.io/5n5jv3seqnhj//content-item-detail-page-switch-environments.png) To set up Visual Editing, check out the [setup doc](/project-setup/setting-up-visual-editing). ### Preview in a separate tab Another option to preview your content item is to click the icon to open the preview in a separate tab. ![preview in separate tab](https://assets-site.prepr.io/6rc70feyxksc//content-item-detail-preview-in-separate-window.png) To set up one or more preview URLs, check out the [setup doc](/project-setup/setting-up-previews). ## Manage versions Content item versioning enables you to do the following tasks: - Reset your last content item edits. - Keep track of all the changes in a content item. - Revert to a previous version when needed. - Look for older versions in your content item. - See every change made in a content item. You can find content item versions in one of the following ways: - Click the date link in the publish info text at the top left to open the activity log. And click the **Show earlier versions** link. ![show earlier versions link](https://assets-site.prepr.io/2siy21uzaf27//content-item-detail-show-earlier-versions.png) - Or click the button to open the dropdown list and choose the **Show version history** option. ![show version history option](https://assets-site.prepr.io/4vu9dux4zraf//content-item-detail-show-version-history.png) You can then see the list of previous versions for this content item. ![versioning](https://assets-site.prepr.io/ibn1c4owr7w//content-item-detail-versions-list.png) Select one of the versions and click **View** to open the specific content item version. The yellow notification bar at the bottom of the page indicates that you are viewing an older content item version. To restore a previous version, click **Restore** to open this version for further editing. Take note of the following when viewing earlier versions: - All fields and drag-and-drop elements are versioned. - There is no version history of the slug and workflow settings. - Content item versioning is available per locale. ## Check the linked items When you edit a content item, you can easily view the content items that reference this content item.\ Simply click the button to open the dropdown list and choose the **Show referring items** option to open the list of linked content items. ![show referring items option](https://assets-site.prepr.io/4vu9dux4zraf//content-item-detail-show-version-history.png) ## Delete a content item You can delete a content item in a couple ways: **From the Content items list** 1. Go to the **Content** tab. 2. Hover over the content item you want to delete to make the actions visible, and click the icon. ![Hover Delete from content item list](https://assets-site.prepr.io/1cc7omcf3eah//delete-a-content-item.png) 3. In the pop-up window, click **Delete** again to confirm the action. - **From the Content item page** 1. Go to the **Content** tab. 2. Click to open a content item you want to delete. 3. Click the button to open the dropdown list and choose the **Delete** option. ![delete option](https://assets-site.prepr.io/4vu9dux4zraf//content-item-detail-show-version-history.png) 4. In the pop-up window, click **Delete** again to confirm the action. ### Delete a language variant If you [manage multi-language content](/content-management/localizing-content), then you also have the option to delete a specific language variant. Click to delete a content item and then choose a preferred option: ![Delete language variant](https://assets-site.prepr.io/39jmmgu9rt7f//delete-a-language-variant.png) ### Recover a deleted item You can recover a deleted item by clicking the *Deleted* view to list all the deleted content items. Hover over the content item you want to recover and click the **Recover** link. ![recover deleted items example](https://assets-site.prepr.io/5ok2ngnitu1x//deleted-view.png) When the **Recover item?** pop-up window appears, click the **Yes, recover** button to confirm. The restored content item no longer appears in the list of deleted items. Click the **All items** view to see your recovered item. ## Bulk actions on content items In some cases you may want to perform certain actions on multiple content items at once. To view and trigger bulk actions, go to the **Content** tab. Hover over the content items and select the checkbox for the content items on which you want to perform the bulk action. ![All bulk actions](https://assets-site.prepr.io/3nhyzuhg1qwq//bulk-actions.png) Let's look at each of these actions in more detail. ### Publish now or later In some cases you might want to publish large batches of content items, such as campaigns or updates that span several pieces of content. You can do this by following the steps below. ![publish content items](https://downloads-site.prepr.io/2wdqo6va0hqa-publish-now-or-later.gif) 1. Choose the content items that you want to publish in the content item list. 2. Click the icon to **Publish now or later**. 3. Click the **Publish** button to publish the content items right away. 4. Or if you want to schedule the content items to be published later, choose a future date and time and click the **Schedule** button. 5. Check the number of content items in the confirmation message and click the **Yes, publish** button or the **Yes, schedule** button. And that's it, you've published multiple content items simultaneously. ### Unpublish now or later In some cases you might want to unpublish large batches of content items, such as outdated articles. You can do this by following the steps below. ![unpublish content items](https://downloads-site.prepr.io/5yz30fifhme6-unpublish-now-or-later.gif) 1. Choose the content items that you want to unpublish in the content item list. 2. Click the icon to **Unpublish now or later**. 3. Click the **Unpublish** button to unpublish the content items right away. 4. Or if you want to schedule the content items to be unpublished later, choose a future date and time and click the **Schedule** button. 5. Check the number of content items in the confirmation message and click the **Yes, unpublish** button or the **Yes, schedule** button. And that's it, you've unpublished multiple content items simultaneously. ### Change workflow stage to In some cases you might want to change the workflow stage of multiple content items, for example, when you've created a batch of content items and need to move them to the *Review* stage. You can do this by following the steps below. 1. Choose the content items in the content item list for which you want to change the workflow stage. 2. Click the icon to **Change workflow stage to**. ![change workflow stage](https://assets-site.prepr.io/4s4zzd5p1bdf//change-workflow-stage-to.png) 3. Choose your desired stage, for example *Review* from the dropdown list. And that's it, you've change the workflow stage for multiple content items simultaneously. ### Assign to In some cases you might want to assign multiple content items to the same user, for example, when you've created a batch of content items and need someone to review them. You can do this by following the steps below. 1. Choose the content items in the content item list you want to assign. 2. Click the icon to **Assign to**. ![change assign](https://assets-site.prepr.io/5b2lhkcg5335//assign-to.png) 3. Choose the user from the dropdown list. And that's it, you've assigned multiple content items to a single user simultaneously. ### Export to In some cases it's necessary to export content from one environment to another, for example, when you want to do system testing in your development environment with realistic content from the production environment. ![export to](https://assets-site.prepr.io/1ro1z7wo4b5d//export-to.png) ### Delete To delete multiple content items at once follow the steps below. 1. Choose the content items you want to delete, by hovering over each content item and clicking each checkbox. 2. To select all content items, click the icon at the top of the list. 3. Click the icon at the top of the list to delete all the selected content items. 4. In the pop-up window, click **Delete** again to confirm the action. ![select bulk delete](https://assets-site.prepr.io/18a5gwtlo9y4//bulk-delete.png) ## Find your content items There are several features listed below to help you find your content items easily. ### Layout options You can use one of the layout options at the top of the *Content* page to find content items easily depending on your needs. #### List When you go to the **Content** tab, the *List* layout opens by default to show a complete list of all of your content items. You can [filter the content items](#filter-options) to narrow down the list. ![List layout](https://assets-site.prepr.io/3avoslaa72hs//list-layout-option.png) #### Calendar Click the *Calendar* icon to get a clear visual overview of all your scheduled items to help you plan upcoming articles or campaigns to avoid overlap. ![Calendar view](https://assets-site.prepr.io/6ub7e9p244xh//calendar-layout-option.png) #### Kanban Click the *Kanban* icon when you want to see a clear overview of content items by their status. ![Kanban view highlight icon](https://assets-site.prepr.io/6z436rjjzmmt//kanban-layout-option.png) #### Content tree Click the *Content tree* icon when you want to see an overview of the relationship between content items in a tree-like hierarchy. The content tree is based on the slug value of content items. ![Content tree example](https://assets-site.prepr.io/5ur92tb7k8ym//content-tree-example.png) If the content tree layout is not visible, request an admin user to [define the parent slug format](/project-setup/setting-up-environments#content-tree-parent-slug-format). ### Filter options Prepr makes it even easier to filter precisely the content you're looking for with **Advanced Content Filters**. You can choose multiple filters to narrow down your search for specific content items. See the complete list of filters below. ![content item filters](https://assets-site.prepr.io/1yortdj7qra9//filter-options.png) #### Locale You can filter content items by a specific locale, for example, `en-US` to select the list of American English versions of content. #### Model You can filter your content by one or more models. For example, to only list the blog posts or to view a list of pages and blog posts. - *Supporting model* - When you choose a model, additional filters are available for all supporting models. You can choose from a list of models that are defined as content references, for example, the **Category** of the *Car* model. - *Stack* - When you choose a model, additional filters are available for any stack fields defined in the model. The filter name matches the name of the [*Stack* field](/content-modeling/field-types#stack-field). - *Enumeration* - When you choose a model, additional filters are available for any enumeration used in the model. The filter name matches the enumeration name, for example the **Size** for the *Product* model. #### Publication status You can filter your content by one or more publication statuses. For example, to list published and scheduled content items. The possible filter values are *Published*, *Scheduled*, *Unpublished changes* and *Not Published*. #### Workflow stage You can filter your content by one or more workflow stages. For example, to list the content items that are in *To do* or *In progress*. The possible filter values are *Done*, *Review*, *In progress*, *To do*, and *Archived*. #### Assignee You can filter your content by one or more assignees. #### Publication date You can filter content items by selecting a date range, including future dates, for example, to filter items scheduled to be published in the future. #### Tags You can filter content items by one or more tags. ### Views You can see the list of views in the left sidebar of the **Content** page. ![view introduction](https://assets-site.prepr.io/4qkbanvaha96//views-introduction.png) The following views are available out of the box and cannot be updated: - *All items* - The default view of all content items without any filter criteria. - *Scheduled* - The list of content items that are scheduled for a future date. - *Experiments* - A view of all content items with adaptive content and A/B tests, in other words a complete list of all your experiments. - *Needs attention* - The list of content items with broken links or could not be published. In this view, you can go to the relevant content - *Deleted* - The list of deleted content items. In this view, you can recover content items that were deleted by mistake, for example. Apart from these views, you can create your own *Shared view* or *Private view*. A *Private view* will only be visible to you, while a *Shared view* will be visible to all users of this environment. When you're viewing all content items and choose some filter criteria, these are retained for a session. So the next time you visit the overview of the content items, the last selected filters will be active. If you often use the same filters in your Prepr environment, you can save these as a view. Make the filter selection and click the **Save as new view** link. Give the view a name and save it. You can also group similar views by moving them into folders. ![content list views example](https://assets-site.prepr.io/b0owkhy5rws//content-list-view-shared-view-in-folder-selected.png) ### Search content items When you type any keyword in the search bar, Prepr performs a fuzzy search on the *Title* field of content items, by default. When you click the search bar, a drop-down list appears with the following additional search options: - *Search on full-text* - Prepr performs a fuzzy search on all text fields and text elements. - *Search on slug* - Enter a partial or exact keyword for this fuzzy search on the *Slug field*. - *Search on ID* - Enter the exact ID of the content item you are looking for. ![content item search](https://assets-site.prepr.io/4c6irdkql27w//search-options.png) Now that you understand each of the core tasks in more detail, review the handy shortcuts below to manage content. ## Manage content items with shortcut keys You can use a number of shortcut keys to manage content items more efficiently. Go to the **Content** tab to view the content item list. From this view, you can use the following shortcuts: - Add a new content item with . If the content item list is filtered by a specific model, this shortcut creates a content item for that model directly. - Select all content items in the list with . - Simply press the `esc` key to deselect any selected content items. - Delete selected content items from the list by pressing the key. Choose and click a content item in the list to make changes to that content item. From a specific content item, you can use the following shortcuts: - Publish the content item with . - Save the content item with . - Close the content item with . From any other page in Prepr, you can press `/` to open the launchbar. The launchbar allows you to do quick searches on content items or any other page you have access to in your Prepr environment. Source: https://docs.prepr.io/content-management/managing-content/managing-content-items --- # Optimizing content for SEO with *Content check* *This article explains how to optimize your content items for SEO (search engine optimization).* ## Search engine optimization SEO (search engine optimization) is the practice of improving your website's content to increase visibility and ranking in a search engine's results with the goal of driving more relevant traffic. You don't need to be an SEO expert to create high-ranking content in search engines when using Prepr. When you want to create optimal SEO values, simply run the *Content check* feature while editing a content item. ## *Content check* 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. ![Example content check results with SEO values](https://assets-site.prepr.io/7cupnkka5riz//example-content-check-results-for-seo-title-and-meta-description.png) For setup details, check out the [model settings](/content-modeling/managing-models#enable-content-check). ## SEO values Prepr checks the following SEO values when you run the *Content check* feature: - SEO title - Meta description - Keywords The SEO title and meta description values come from fields in a model or component that are marked as the **SEO title** and **Meta description**. Check out the [field setup guide](/content-modeling/field-types#item-title-and-seo-fields) for more details. ![Example SEO component with SEO title and meta description](https://assets-site.prepr.io/27cf5q7gr2cy//example-seo-component.png) In addition to checking the length of the SEO title and meta description, the *Content check* makes AI suggestions for alternative values that meet the guidelines: - SEO title - Recommended length between 50 and 60 characters - Meta description - Recommended length between 120 and 160 characters - Keywords - If keywords exist, they should exist in the SEO title or meta description, or they shouldn't be duplicated too many times in the SEO title or meta description. ## Adding keywords When you run the *Content check* for a content item, and there are no keywords, you can add keywords to improve the SEO for this content item by clicking the **Add keywords** link. ![example content check - add keywords dialog box](https://assets-site.prepr.io/49i3fjhjys7v//add-keywords-example.png) For best practices on handling SEO for development, check out the [SEO best practices guide](/development/best-practices/seo). Source: https://docs.prepr.io/content-management/managing-content/optimizing-content-for-seo --- # Creating rich content *Easily create rich content using basic features in Prepr.* ## Introduction This article shows you how to enrich your content in different ways: - Using the [*Dynamic Content Editor*](#using-the-dynamic-content-editor). - [Adding content references](#adding-content-references) to link different content items. - [Adding links](/content-management/managing-content/creating-rich-content#adding-internal-and-external-links) to reference external resources. ## Using the Dynamic content editor ![Dynamic content editor](https://assets-site.prepr.io/ia6xh9gccby//creating-rich-content-dynamic-content-editor.png) In the *Dynamic Content Editor*, you can enrich your content using the following elements: - **Paragraph** The paragraph element contains a number of formatting options. You can use **bold text**, *italic*, and . Bullets (ordered and unordered), links, and tables are also available. - **Headings** Depending on the settings, you can choose up to six levels of headings to match your content item. You can easily change a heading element to another heading or other text element by making a selection from the drop-down options. - **List** You can add an ordered or unordered list. Like the paragraph, you can apply a number of formatting options. - **Table** You can add a table with up to 10 rows and 10 columns. - **Code** You can paste a code snippet in your content, for example, HTML. - **Media** Depending on the settings on the [dynamic content field](/content-modeling/field-types#dynamic-content-field), select the icon to add one or more images, videos or files. You could also edit captions, set the alignment or define image presets. [Learn more about image presets and alignment](/content-management/managing-assets/editing-and-configuring-assets). - **Social post embeds** Social elements are embeds from the largest social media platforms, namely, Twitter, Facebook, Instagram, Spotify, Youtube, SoundCloud, vimeo, TikTok, Apple Podcast, Bluesky, and Threads. To embed a social post, choose the corresponding social media icon and insert the URL of the social post. - **Location** Click the icon to add a location based on a Google Map address or coordinates. - **Integrations** If you need to reference content in an external CMS, a legacy system or an eCommerce platform, click the corresponding integration icon and choose the integrated content. Prepr will keep the data in sync automatically. Check out more details in the [integrations](/integrations) docs. - **Component** If a component is defined and included in the settings of the dynamic content field, you can embed a component by clicking on the corresponding icon. By using a component, you can add empty elements to your dynamic content. This way you can trigger the front end to insert static front-end components, such as banners, marketing widgets, or forms. Check out more details in the [components](/content-modeling/managing-components) doc. There are several ways to edit your content in the *Dynamic Content Editor*: - **Add an element.** To add a new element, do one of the following: - Enter **/** to see a pop-up with all the elements. - Click an element icon in the toolbar below. - Press ENTER to add a new paragraph and SHIFT ENTER to add a break line. - From the element icon on the left, click the **Add element below** button. - **Multi-select *Text* elements.** You can select multiple text elements to copy or delete them. - **Change the element type.** To change an element to another element type, click the element icon on the left and select the new element type from the drop down. Note that you can only change a filled element type to an element of the same type. For example, a paragraph can be changed to a heading, but not to a media file. - **Sort elements.** To change the position of an element, click the element icon on the left and click the or button. - **Remove elements.** To remove a text element from the dynamic content field, do one of the following: - Empty the element and enter BACKSPACE. - Click the element icon on the left and click the button. ## Adding content references The content reference is a super-fast way to link related items to your content item. The content reference field is often used for linked content items, such as authors, categories, or as manually picked related items. There are three options to display the content reference field, depending on your needs: as a modal window, as an autosuggest, or as checkboxes/radio buttons. You can make your choice in the [Reference field settings](/content-modeling/field-types#content-reference-field). - **Modal window**. This option combines searching and adding new items. You can also add a filter to quickly find the related item you need. If the item you need is not present, you can create it there and then. ![Content item modal example with filter options](https://assets-site.prepr.io/66g35692of4g//new-content-item-modal-with-example-filter.png) - **Auto-suggest**. You can use autosuggest if you need a specific content item quickly, without having to search extensively. Start typing in your input field and the results will appear immediately. ![auto suggest](https://assets-site.prepr.io/1nrsjp8sn6ig//creating-rich-content-content-reference-dropdown-list.png) - **Checkboxes**. This option is best used if you only have a limited set of content items 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. ![checkboxes](https://assets-site.prepr.io/3vthzhk0g89p//creating-rich-content-content-reference-checkboxes.png) ## Adding internal and external links ### Dynamic internal links The Internal links are references to items or assets in Prepr. You can refer to other content items or assets in a text editor or the *Dynamic Content Editor*. To create an internal reference, click the **Insert item link** icon in the toolbar of the text editor and choose whether you want to link to a content item or an asset. Select the item or asset in the media browser and insert the link. ![dynamic internal links](https://assets-site.prepr.io/231oavgvnsoq//creating-rich-content-internal-link.png) The created link is dynamic, this means that as soon as the title, slug, or URL of the linked content item or asset changes, the link will update dynamically. This way you never have to deal with dead links in your text again. Check out the [dynamic content field API reference](/graphql-api/schema-field-types-dynamic-content-field#links-text) on how to query the internal link. ### External linking options You can link to an external URL using the **Link option**. If *Links* are enabled on a text field or the *Dynamic content Editor*, you can add an external link to your text. To add an external link, click the icon to make an in-line reference. Enter the URL, and the link text, and decide whether this link needs to be opened in a new tab or not. For SEO purposes, you can also select the Don't follow option. ![insert link](https://assets-site.prepr.io/739x5wty2hev//content-item-detail-dont-follow-tag.png) To edit the added link, simply click anywhere on the link text and click **Edit link** to make changes in the URL or in the link text. ## Adding remote content When you need to add content that is sourced from an external system, and the [remote source is set up in Prepr](/content-modeling/creating-a-custom-remote-source), you can simply you’ve connected to the external system and you can add the remote content to a content item using the following steps: 1. Navigate to the **Content** tab and click the desired content item from the list. 2. In the remote content section, click the button to add new items (in our example – **Add product**), search through the catalog or use a filter to find and add the desired items to the content item. 3. Save and publish this content item to complete the setup. ![Add remote content to a content item](https://assets-site.prepr.io//6ahgjm6yqg73-choose-remote-items-with-filters.png) That’s it. Now your web page includes 3rd party content. Prepr will synchronize your remote content automatically to keep it up to date. Source: https://docs.prepr.io/content-management/managing-content/creating-rich-content --- # Introduction to Assets *From this article, you’ll learn what assets are and which asset types are available in Prepr.* ## What are assets? *Assets* are media files such as images, video, audio, and other digital files you can use on your web pages to enrich content. With the growing demands of an internet business, brands have to do more to stand out and meet the rising expectations of potential customers. Rich content has a crucial role in attracting and keeping your audience. Prepr allows you to easily create content pages filled with rich media assets. Let's look at them in detail. ## Assets in Prepr An *Asset* in Prepr is a media file, such as an image, audio, video, live stream, or another file type, that lives in one organized storage — [*the Media Library*](/content-management/managing-assets/managing-assets). You only need to upload digital assets to Prepr once, and you can reuse them on multiple web pages. Prepr automatically deploys and serves all media assets over a high-performing *Content delivery network (CDN)*. A CDN stores a cached version of content and puts it in many places simultaneously. This improves page load speed and accelerates content delivery. Prepr supports the most popular image formats and provides automatic image optimization with *WebP encoding technology*. The WebP format makes your web pages load faster, frees up storage space, and guarantees high image quality. The following table lists the asset types in Prepr and their supported media formats. | Asset type|Description|Supported formats| | -------------------------------------------- | ----------------------------------------------|---------------------| | [Image](/content-management/managing-assets/introduction-to-assets#image) | Image files such as photos. | JPG, JPEG, PNG, BMP, SVG, GIF and more. **Note:** WebP graphics are supported through the *File* asset in Prepr. | | [Video](/content-management/managing-assets/introduction-to-assets#video-and-audio) | Video files and live video streams. | MOV, M4V, MPG, MP4, and more. | | [Audio](/content-management/managing-assets/introduction-to-assets#video-and-audio) | Audio files. | MP3, M4A, WAV, and more. | | [File](/content-management/managing-assets/introduction-to-assets#file) | Archives, documents, and vector images. | ZIP, PDF, XLSX, DOCX, and WebP. | ### Image There’s a wide range of image options in the Prepr Editor interface and through the API. For example, image presets for different device types, cropping, captions, and more. Read more about [adding images to your web application](/development/best-practices/assets/images). ### Video and Audio You can enrich your web pages with audio and video content or broadcast live video streams thanks to the *Prepr and Mux Video integration*. This integration gives you the benefits of seamless multi-channel content delivery and cutting-edge video processing technologies. *Mux Video* accepts most modern video formats and codecs. And you get automatic video transcoding, audio normalization, and high-quality live streaming with the *HLS (HTTP Live Streaming)* protocol out of the box. Prepr uploads your media files to Mux automatically, so you do not need to have a Mux account yourself. Follow our step-by-step guides to [post audio and video content](/development/best-practices/assets/video-audio) or [stream your live video](/development/best-practices/assets/live-video-stream) in a web application. ### File With Prepr, you can add different file types to your web application, such as PDF, ZIP, and more. You can also use the *File* asset to work with WebP graphics in Prepr. Find more details in the [Files guideline](/development/best-practices/assets/files). ## Where to start? To start with, learn how to create and where to store assets in Prepr. Please check out the [Manage assets](/content-management/managing-assets/managing-assets) guide. Source: https://docs.prepr.io/content-management/managing-assets/introduction-to-assets --- # Managing assets on the *Media* page *This article explains where assets live in Prepr and which actions you can perform on them.* ## Introduction You can find all your digital assets in one place in Prepr using the **Media** page. This makes it easy to access, view, and manage your assets. You can directly upload, edit, download, replace, delete, organize, and find assets from the *Media* page. For Mux videos, you can also replace thumbnails and add subtitles. Let's dive into each of these actions in more detail. ## Uploading assets To upload an asset, follow the steps below. 1. Simply drag and drop the asset/s directly from your local drive. ![Drag asset](https://assets-site.prepr.io/5qi5rspc25dr//drag-assets-to-upload.png) 2. Or at the top of the **Media** page, click the **Upload asset** button to open your file explorer. 3. Choose the asset/s you want to upload and click the **open** button. You'll see the progress of asset/s in each thumbnail while they're uploading. ![Upload an asset](https://assets-site.prepr.io//6vlohvr20h3l-media-page-uploading-assets.png) You can then click the thumbnail of the assets you want to view. ## Editing assets To edit a specific asset, go to the **Media** tab and click the thumbnail of the asset to open it. You can update some of the asset fields below directly in the *Asset* page. ![Asset details](https://assets-site.prepr.io//3l9datzgtb8p-example-asset.png) - **Internal name** - This field is required and is used to enter the *Title* of the asset. - **Description** - This optional field is used by editors to describe the asset. - **Author** - This optional field can be used to enter the name of the photographer or the visual designer of the asset. - *Additional fields* - Any additional fields can be added to the **Asset** model, such as **Copyright info**. For more details, check out the [Asset model doc](/content-modeling/defining-the-asset-model). - **Tags** – Allows you to [add one or more tags to an asset](#tags). - **Collections** – Allows you to [group assets into collections](#collections). - **Used in** - The list of all content items that use this asset. To edit the asset details, simply update the applicable fields and click the **Save and close** button. In the sidebar of the *Asset* page, you can see the following generated data: - **Optimized URL** – The URL you can use to include the asset in your front end. - **Download URL** – The URL you can use to download an original asset file. - **Asset ID** – The unique identifier of an asset you can refer to in API requests. - **Playback ID** – The public Mux Playback ID for videos. - **Metadata** – The date and time when an asset is created and changed. ### Multiple locale assets When localization is enabled in the Asset model, additional fields will be available for each locale allowed in your environment. ![Example asset - multiple locale field](https://assets-site.prepr.io/6agj837klc5v//example-asset-multiple-locale-field.png) For more details on the setup, check out the [Asset model doc](/content-modeling/defining-the-asset-model#enable-localization-in-assets). ## Downloading an asset In the *Asset* page, you can download this asset to your local storage, by clicking the **Download** button in the sidebar. ![Dowload an asset](https://assets-site.prepr.io//5l37m1nz6f4y-editing-assets-download.png) The original file will be saved to your default download folder. ## Replacing an asset In the *Asset* page, you can replace an existing file with a new one by clicking the **Replace** button to choose the replacement file from your local storage. ![Replace an asset](https://assets-site.prepr.io//61sutgcmgx0i-editing-assets-replace.png) ## Deleting assets In the *Asset* page, you can delete an individual asset if you no longer need it, by simply clicking the **Delete** button. ![Delete an asset](https://assets-site.prepr.io//1rljxxwowdvy-editing-assets-delete.png) In the confirmation dialog window, click the **Yes, delete** button to confirm the delete. You can also delete multiple assets by following the steps below. 1. Go to the **Media** tab and select assets by hovering over each thumbnail and clicking the icon. To select all assets, click the icon in the top action menu. 2. In the top action menu, click the icon to delete the selected assets. ![delete multiple assets](https://assets-site.prepr.io//5w8z2h3d1fe9-media-page-delete-multiple-assets.png) 3. In the confirmation dialog window, click the **Yes, delete** button. ## Organizing assets In Prepr, you can organize your assets in a way that works for you. For example, choose to group assets into collections, add tags, or do both for better categorization and precise search. Find out more below. ### 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 profile pictures, banners, stock photos, etc. Let's look at how to organize assets using collections in more detail. #### Create a collection To create a collection, follow the steps below. 1. Go to the **Media** tab. 2. In the top action menu, click **+ Add collection**. 3. Enter the title for a collection and click **Add** to confirm. ![Add a collection](https://assets-site.prepr.io//2r7qdd9jtf26-media-page-add-collection.png) #### Add assets to a collection Once the collection is created, you can add multiple assets to your collection using one of the steps below. 1. Go to the **Media** tab and select assets by hovering over each thumbnail and clicking the icon. To select all assets, click the icon in the top action menu. And click the icon. ![Add multiple assets to a collection](https://assets-site.prepr.io//78k2cbr831m8-media-page-add-assets-to-collection.png) 2. Or, click the collection folder to open the collection and click the **Add assets** button. In the dialog window, you can then select existing assets you want to add to the collection or click the **Upload assets** button to upload a new asset to add to the collection. To add a single asset to a collection, follow the steps below. 1. Go to the **Media** tab and click the thumbnail of an asset to open it. 2. At the bottom of the *Asset* page, click the **+ Add to collection** link in the *Collections* section. 3. Choose a collection from the drop-down menu. 4. On the right-hand sidebar, click **Save and close** to apply the changes. #### Remove assets from a collection You can remove multiple assets from a collection in the *Collection* page or a single asset in the *Asset* page. To remove several assets from a collection, follow the steps below. 1. Go to the **Media** tab and click the collection folder to open the *Collection* page. 2. Select the assets you want to remove by hovering and clicking the icon on each of the thumbnails. 3. Click the icon in the top action bar to remove the assets from this collection. ![Remove multiple assets from a collection](https://assets-site.prepr.io//oxg7fr42fax-media-page-remove-assets-from-collection.png) To remove a single asset from a collection, follow the steps below. 1. Go to the **Media** tab and click the asset to open it. 2. On the *Asset* page, go to the **Collections** section and hover over the collection. 3. Click the icon to remove the asset from the collection. 4. On the right-hand sidebar, click **Save and close** to apply the changes. #### Set a collection cover A collection cover gives you a first impression of the assets in a collection. The first added asset is the collection cover by default. To change the cover, first click the collection folder at the top of the **Media** page to open it. Hover over the thumbnail of an asset and click the **Set as cover** link. ![Set a collection cover](https://assets-site.prepr.io//6mkuved8rb0k-collections-set-as-cover.png) #### Update a collection title To update a collection title, first click the collection folder at the top of the **Media** page to open it. Then, click the name of the collection to edit the *Title* or click the icon and choose the **Edit collection** option. In the dialog window, enter a new title and click the **Save** button. #### Delete a collection To delete a collection title, first click the collection folder at the top of the **Media** page to open it. Then, click the icon and choose the **Delete collection** option. In the confirmation window, click the **Yes, delete** button. ### Tags A *Tag* is a meaningful label you can assign to your assets to differentiate between them while filtering. You can add tags to multiple assets or to a single asset in the *Asset* page. To tag several assets at once, follow the steps below. 1. Go to the **Media** tab and select assets by hovering over each thumbnail and clicking the icon. 2. In the top action menu, click the icon. 3. Choose an existing tag or type a new one. 4. Click the **Add tags** button. ![Tag multiple assets](https://assets-site.prepr.io//4esfp69xex4p-media-page-add-tags-to-asset.png) To tag a single asset, follow the steps below. 1. Go to the **Media** tab and click the asset to open it. 2. At the bottom of the **Asset** page, click the *Tag* field. 3. Choose an existing tag or type a new one. 4. On the right-hand sidebar, click the **Save and close** button to apply the changes. That’s it. You have organized your assets in the Media Library. Now it's easier to find the right one. Let's see how to do this in the next paragraph. ## Finding assets Prepr gives you multiple search and filter options to find the assets you need with ease: - Search the assets by the asset title or keywords in the asset description. - Filter the assets by *Asset type*, *Tags*, *Created on* date, or the *Unused* checkbox. - You can also filter assets by [enumeration field values in the Asset model](/content-modeling/defining-the-asset-model#add-fields-to-the-asset-model), for example, to find a specific license holder. ![Filter and search assets](https://assets-site.prepr.io//3n8wj0wwtbhk-media-page-search-and-all-filters.png) ## Replacing video thumbnails By default, a thumbnail image is taken from the middle of the video based on the Mux *Playback ID*. Still, you can set a custom video thumbnail in Prepr as follows: 1. Go to the ** Media** tab and click the thumbnail of the video asset that you want to edit. 2. On the **Asset** page, hover over the thumbnail and click the icon. 3. Choose the replacement image file to replace the thumbnail. ![Replace thumbnail](https://assets-site.prepr.io//6jlisg3o9zrl-replace-video-thumbnail.png) ## Adding video subtitles You can add subtitles to your Mux videos in Prepr to provide multilingual support to your web app visitors and extend the web app accessibility. To add subtitles, follow the steps below. 1. Go to the ** Media** tab and open the needed video file. 2. On the **Asset** page, click **+Add Subtitle**. 3. Choose a locale, and upload either an *SRT* or *WebVTT* file containing the subtitle information. Prepr will automatically generate a subtitle URL and add it to the video in Mux. ![Add subtitle](https://assets-site.prepr.io//2h9drwg9bhsn-add-subtitle.png) There's no limit on the number of subtitle files you can include in your video asset. Each subtitle file will be stored as an individual file asset in Prepr. [Learn more on how to add videos to your web app](/development/best-practices/assets/video-audio). Source: https://docs.prepr.io/content-management/managing-assets/managing-assets --- # Using assets in content items *This guide describes the Prepr features you can use to edit and configure assets when adding them to your web application.* ## Introduction Media files can enrich your website content only when they are qualitative and usable. For instance, images should be optimized for a device and presented at the highest resolution possible. Likewise, having a well-described video with the key cues in your audience’s native language increases the chances your customers will watch the content. In other words, the way you configure your assets significantly affects your content usability. The following options are available for you to edit and configure assets in your content item: - Adding captions - Setting alignment - Setting an image focal point - Cropping images - Setting a download filename Before configuring your assets though, let's first look at how to add assets to a content item. ## Adding assets to a content item If [asset fields are defined in the model](/content-modeling/field-types#assets-field) of your content item, you'll see an asset block for each asset field. Check out more details on [the supported assets in Prepr](/content-management/managing-assets/introduction-to-assets#assets-in-prepr). To add assets to a content item, simply drag and drop the asset file from your local storage to this block, or click it to open the media window dialog to choose an existing file in Prepr. ![Add assets to content items](https://downloads-site.prepr.io/5adn9ct7nz9k-adding-assets-to-a-content-item.gif) From this window, you can also click the **Upload asset** button instead to choose the files you want to upload and add them to your content item. Once done, click the **Add x assets** button to add these to the content item. Now that you know how to add assets to a content item, let's dive into different display options for the images. ## Setting alignment The *Alignment* feature lets you position a digital asset within the text elements on a web page. You can choose from the following options: - **Left** – aligns the left edges of an asset and text element. - **Center** – aligns the center points of an asset and text element. - **Right** – aligns the right edges of an asset and text element. To align an asset, a developer can [enable the *Allow alignment* toggle in the asset field settings](/content-modeling/field-types#assets-field-settings). 1. On the **Content item** page, hover over an image and click the icon in the top right corner. 2. Select the desired alignment option. ![Align options](https://assets-site.prepr.io/641bwkq0r4t2//assets-set-alignment.png) ## Adding captions The *Caption* feature lets you create multiple descriptions for a single asset every time you use this asset in a content item or a content item locale. While the [*Asset Description* field](/content-management/managing-assets/managing-assets#editing-assets) is recommended for internal use, captions are helpful in the following cases: - When you need to describe a single asset across multiple content items. - When you need to describe a single asset in a multi-language content item. To create a caption for an asset, a developer can [enable the *Allow caption* toggle in the asset field settings](/content-modeling/field-types#assets-field-settings). 1. On the **Content item** page, hover over the image thumbnail and click the icon in the top right corner, then click **Edit caption**. ![Edit caption for an asset](https://assets-site.prepr.io/1ef81f85sgup//assets-edit-caption.png) 2. In the opened dialog window, type your text, then click **Save** to apply your caption. ## Setting an image focal point An image focal point is the key area that you want to remain visible regardless of how the image is resized. It ensures that important parts of the image (such as a person’s face or a product) stay in focus when displayed across different screen sizes or aspect ratios. If the [set image focal point option is enabled](/content-modeling/field-types#assets-field-settings), you can choose the focal point for an image when adding or editing the image in a content item . ### Set focal point for new image Follow the same process above to [add images to a content item](#adding-assets-to-a-content-item). When adding an image to a content item and a focal point is required in the [asset field settings](/content-modeling/field-types#assets-field), you'll see the **Set focal point** button at the bottom of the *Media* dialog window. 1. Click the **Set focal point** button to open the *Set focal point* modal. ![set focal point new image](https://assets-site.prepr.io/4a1rb4m23dm8//set-focal-point-for-new-image.png) 2. Move the focal point indicator to the part of the image you always want visible and click the **Add 1 asset** or the **Next asset** (in the case of multiple assets) button. 3. When you've set the focal image for multiple images, simply click the **Add x assets** button. ### Set focal point for existing image 1. On the **Content item** page, hover over the image and click the icon in the top right corner to open the *Set focal point* modal. 2. Choose the focal point for the selected image and click the **Save** button. ![set focal point gif](https://downloads-site.prepr.io/164qz79s9dj3-setting-an-image-focal-point.gif) ## Cropping images *Cropping* an image is important when adding it to your content. You crop images to look great on all devices, such as mobile, desktops, and tablets.\ With Prepr, you can crop image files easily, without altering the original stored files. To enable cropping on images, developers can define the image presets. Check out the [*Assets* field settings](/content-modeling/field-types#assets-field) for more details. When you add images to content items and crop them according to the presets, a developer can retrieve the chosen presets using the GraphQL API to render them accordingly in the web app. For that, they need to specify a preset name in the API request. For more details, see the sample query for retrieving *Presets* in the [GraphQL API reference](/graphql-api/schema-field-types#images). Alternatively, a developer can transform images themselves using the API. For more information, check out the [REST API](/mutation-api/assets-resizing) or the [GraphQL API](/graphql-api/schema-field-types#images). ### Crop new images Follow the same process above to add images to a content item. When adding an image to a content item and cropping is required in the [asset field settings](/content-modeling/field-types#assets-field), you'll see the **Crop x assets** button at the bottom of the *Media* dialog window. ![Crop required - Add new images](https://assets-site.prepr.io//3r4171ayqdxb-crop-required-add-new-images.png) 1. Click the **Crop x assets** button to open the crop images window. ![Crop new images in a content item](https://assets-site.prepr.io//3pyxawnvl8f-crop-multiple-images.png) 2. Simply choose the preset and move the crop area over the part of the image that you want cropped. 3) If there are multiple presets, simply click the thumbnail of the next preset to add its crop. 4) When cropping multiple files, click the next image thumbnail in the bottom left corner to crop another image or click the **Next asset** button. 5) Once done, click the **Add x assets** button to add the cropped images to the content item. ### Crop existing images When cropping is not set to required, you can add a crop after the image has already been added to a content item. To crop an existing image in a content item, complete the following steps for each image: 1. On the **Content item** page, hover over the image and click the icon in the top right corner, then click **Crop image**. Or click the icon on the image thumbnail to open the crop editor quickly. ![Crop image](https://assets-site.prepr.io/1fwnr0lwt086//assets-crop-image.png) 2. In the crop editor window, select a preset and an area in your crop by dragging the points or moving the entire crop area. 3. Click **Save** to apply the updated cropped image. ![Crop existing images in a content item](https://assets-site.prepr.io//2s8d01oah8ir-crop-image.png) ### Edit image crop If you want to change the current crop, complete the following steps for each image: 1. On the **Content item** page, hover over the image and click the icon in the top right corner, then click **Edit crop**. Or simply click the icon to open the crop editor window and follow the same steps as above. ![Edit crop](https://assets-site.prepr.io/4kdq4ytxkzuz//assets-crop-image.png) ### Delete image crop To delete a crop, hover over the image thumbnail in the *Content item* and click the icon in the top right corner. Then, choose the **Delete crop** option. ![Delete crop](https://assets-site.prepr.io/w_1920/2lsltx43ptu6-05-delete-crop.png) ## Setting a download filename When you need to provide a download URL link in your content item to make a file available to web app visitors for download, you can set a parameter in the URL to define the filename. For example: `https://acme-company.files.prepr.io/24eovl6bs4q-guide.pdf?filename=the-best-guide-ever.pdf` If you don't set this filename parameter, the filename in the URL is used as is. In the example above, this would be `24eovl6bs4q-guide.pdf`. Source: https://docs.prepr.io/content-management/managing-assets/editing-and-configuring-assets --- # Introduction to the Next.js complete guide *This section introduces you to the complete guide that shows you how to connect Prepr to a Next.js project including styling, adaptive content, and A/B testing and a preview bar.* At the end of the complete guide, you’ll have a working website with personalization and A/B testing like the images below. You can customize this project to fit the requirements for your web app. **Home page for general website visitors** ![Dynamic home page](https://assets-site.prepr.io/p6rja5r1cj8//dynamic-website-with-prepr-content.png) **Two variants of a running A/B test on a landing page** ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) **Personalized home page for electric car lovers** ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) ## Prerequisites Make sure the following is in place before getting started: - [A free Prepr account](https://signup.prepr.io/?plan=free) - [An environment with Acme Lease demo data in Prepr](/project-setup/setting-up-environments#create-an-environment) - [The latest version of Node.js](https://nodejs.org/en/download) Now that you know what to expect and have your Prepr environment ready, you can get started with the first step to [set up the Next.js project](step-1-set-up-a-nextjs-project). Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/introduction --- # Set up a Next.js project *The instructions below will guide you through the first step of the Next.js complete guide. These show you how to create a Next.js website with static components.* ![Next.js site with static components](https://assets-site.prepr.io/6e4vb1yxyp5z//static-website.png) You can also watch the video for step-by-step instructions detailed in the guide below. ## Create a Next.js website with static components If you have an existing Next.js project then you can skip this section and continue with the next section to [make your Next.js project dynamic with Prepr content](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic). Otherwise, let's get started. Great work on getting your static web app working! Continue your journey to the next section to [make your Next.js project dynamic with Prepr content](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic). Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/step-1-set-up-a-nextjs-project --- # Make your Next.js project dynamic *This guide shows you how to connect an existing Next.js project to Prepr to retrieve and show Acme Lease demo content.* You can also watch the video for step-by-step instructions detailed in the guide below. ## Connect your Next.js website to Prepr The steps below continue from the previous section, [Set up a Next.js project](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-1-set-up-a-nextjs-project). If you don't yet have a Next.js website with static pages, follow the steps in this section first. Otherwise, let's get started. Congratulations! You have successfully connected your front end to Prepr to make your website dynamic. Continue your journey to the next section to [set up data collection](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection). Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic --- # Set up data collection with tracking and the Prepr Next.js package *Prepr is a CMS that includes built-in A/B testing and personalization features. These capabilities require visitor data to measure your test results and to build segments for personalization. This chapter of the Next.js complete guide shows you how to enable tracking to collect this data in your Next.js front end and how to simplify this data collection with the Prepr Next.js package.* You can also watch the video for step-by-step instructions detailed in the guide below. The steps below continue from the previous section, [Make your Next.js project dynamic](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-2-make-the-project-dynamic). If you don't yet have a Next.js project connected to Prepr, follow the previous steps listed in the [Complete guide overview](/connecting-a-front-end-framework/nextjs/next-complete-guide) to create one. Otherwise, let's get started. ## Install the Prepr Next.js package We've provided the [Prepr NextJS package](https://github.com/preprio/prepr-nextjs) to simplify working with event data for A/B testing and personalization. In the steps below, you'll enable tracking in your website by adding the *Prepr Tracking Code* to your front end. This code generates the `__prepr_uid` cookie for each website visitor. This visitor gets stored in Prepr as a *Customer* with this unique ID, if they don't already exist. This means you can use this `__prepr_uid` cookie value to set the API request header, `Prepr-Customer-Id`, when you retrieve the page content for A/B testing and personalization. The *Prepr NextJS package* prepares the `Prepr-Customer-Id` API request header for you, using the `__prepr_uid` cookie value. Based on this value, Prepr retrieves the right content as follows: - A/B testing: Prepr decides which variant, A or B, to return in the content. - Personalization: Prepr checks the segment that this customer belongs to and retrieves the matching personalized variant. To install the *Prepr NextJS package*, follow the steps below. 1. In your Next.js project, stop the localhost website server (`CTRL-C`) if it's running and install the package with the following terminal command: ```bash copy npm install @preprio/prepr-nextjs ``` Once done, you need to call a function in the package to prepare the API request headers before the page gets rendered in your website. 2. To do this, go to your project and create a new file `proxy.ts` in the `src` folder. Then add the following code to perform the package's preprocessing logic on user requests. ```ts filename="./src/proxy.ts" copy import { NextRequest } from 'next/server' import createPreprMiddleware from '@preprio/prepr-nextjs/middleware' export async function proxy(request: NextRequest) { return createPreprMiddleware(request, { preview: false }) } ``` ## Enable Prepr tracking and collect view events Congratulations! You've successfully enabled Prepr tracking in your Next.js front end, started collecting page view events, and installed the Prepr Next.js package for A/B testing and personalization. Now, you're ready to [add A/B testing](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-4-add-ab-testing) and [personalization](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection --- # Add A/B testing to your Next.js website *Prepr CMS enables editors to create A/B tests directly within their content. This means testing different content versions is simple and effective. This chapter of the Next.js complete guide demonstrates how to set up A/B testing in Prepr, including testing the display of variants and measuring the results.* At the end of this section, you'll see the A and B versions on the *Electric Lease Landing Page*. ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) The steps below make use of the A/B test in the *Electric Lease Landing Page* content item from the Acme Lease demo data. ![A/B test in Electric lease content item](https://assets-site.prepr.io/6l4bf1thuzjc//ab-test-example-electric-landing-page.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Next.js project, follow the steps in this section first. Otherwise, let's get started. You can also watch the video for step-by-step instructions detailed in the guide below. ## Set up A/B testing for the *Electric Lease Landing Page* You can run an A/B test on parts of a web page to show two different versions of the content to different visitors and compare which variant is more engaging. To show the right variant to the right visitor: - Every visitor gets an ID that resolves to an A or a B variant. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. By [installing the Prepr Next.js package](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection#install-the-prepr-nextjs-package) in the previous section, you've already prepared your API request headers. Congratulations! You have a running A/B test with metrics in your Next.js website. Now, you can [Add personalization](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/step-4-add-ab-testing --- # Add personalization to your Next.js website *Prepr CMS enables editors to create adaptive content directly in their content items to personalize elements of web pages. This makes setting up personalization really simple and effective in increasing engagement and conversions. This chapter of the Next.js complete guide shows you how to add personalization to your Next.js website.* At the end of this section, you'll see a personalized home page for visitors interested in electric cars. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) The steps below make use of the Adaptive content in the *Homepage* content item from the Acme Lease demo data. ![Home page content item](https://assets-site.prepr.io/3kzih4y0123a//acme-lease-homepage-adaptive-content-hero-and-feature-sections.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Next.js project, follow the steps in this section first. Otherwise, let's get started. You can also watch the video for step-by-step instructions detailed in the guide below. ## Set up personalization for the home page You can show different personalized versions of the content to different groups (*Segments*) of visitors. To show the right variant to the right visitor: - Every visitor is given an ID that resolves to a segment they belong to. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. By [installing the Prepr Next.js package](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-3-set-up-data-collection#install-the-prepr-nextjs-package) in the previous section, you've already prepared your API request headers. Congratulations! You have successfully set up personalization with metrics in your Next.js website. Now, you can [install the preview bar](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-6-install-the-preview-bar) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/nextjs/next-complete-guide/step-5-add-personalization --- # Install the *Prepr preview toolbar* *This guide shows you how to install the Prepr preview toolbar to easily review A/B testing and Adaptive content directly in your Next.js website.* At the end of this section, you can use the Prepr preview toolbar in your website. ![Prepr preview toolbar](https://assets-site.prepr.io/545864k940pz//prepr-preview-toolbar.png) You can also watch the video for step-by-step instructions detailed in the guide below. ## Add the *Prepr preview toolbar* to your website The steps below assume that you already have [A/B testing](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-4-add-ab-testing) or [personalization](/connecting-a-front-end-framework/nextjs/next-complete-guide/step-5-add-personalization) set up in your Next.js website. If you haven't yet added A/B testing or personalization, follow the steps in these sections first. Otherwise, let's get started. ## All done Congratulations! You have successfully installed the Prepr preview toolbar in your Next.js website. This brings you to the end of the Next.js complete guide which has given you all the tools and tips you need to create your own web app connected to Prepr CMS complete with personalization, A/B testing and a preview bar. Don't hesitate to [give us feedback](mailto:feedback@prepr.io) on your experience using this guide. ## Next steps To learn more on how to expand your project, check out the following resources: - [Content modeling examples](/content-modeling/examples) - [More data collection details](/data-collection) - [More about A/B testing](/ab-testing) - [More about personalization](/personalization) - [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-complete-guide/step-6-install-the-preview-bar --- # Introduction to the Nuxt complete guide *This section introduces you to the complete guide that shows you how to connect Prepr to a Nuxt project including styling, adaptive content, A/B testing and the visual editing setup.* At the end of the complete guide, you’ll have a working website with personalization and A/B testing like the images below. You can customize this project to fit the requirements for your web app. **Home page for general website visitors** ![Dynamic home page](https://assets-site.prepr.io/p6rja5r1cj8//dynamic-website-with-prepr-content.png) **Two variants of a running A/B test on a landing page** ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) **Personalized home page for electric car lovers** ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) ## Prerequisites Make sure the following is in place before getting started: - [A free Prepr account](https://signup.prepr.io/?plan=free) - [An environment with Acme Lease demo data in Prepr](/project-setup/setting-up-environments#create-an-environment) - [The latest version of Node.js](https://nodejs.org/en/download) Now that you know what to expect and have your Prepr environment ready, you can get started with the first step to [set up the Nuxt project](step-1-set-up-a-nuxt-project). Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/introduction --- # Set up a Nuxt project *The instructions below will guide you through the first step of the Nuxt complete guide. These show you how to create a Nuxt website with static components.* ![Nuxt site with static components](https://assets-site.prepr.io/2hkb8jfxzj9y//nuxt-website-with-static-components.png) ## Create a Nuxt website with static components If you have an existing Nuxt project then you can skip this section and continue with the next section to [make your Nuxt project dynamic with Prepr content](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-2-make-the-project-dynamic). Otherwise, let's get started. Great work on getting your static web app working! Continue your journey to the next section to [make your Nuxt project dynamic with Prepr content](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-2-make-the-project-dynamic). Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-1-set-up-a-nuxt-project --- # Make your Nuxt project dynamic *This guide shows you how to connect an existing Nuxt project to Prepr to retrieve and show Acme Lease demo content.* ## Connect your Nuxt website to Prepr The steps below continue from the previous section, [Set up a Nuxt project](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-1-set-up-a-nuxt-project). If you don't yet have a Nuxt website with static pages, follow the steps in this section first. Otherwise, let's get started. Congratulations! You have successfully connected your front end to Prepr to make your website dynamic. Continue your journey to the next section to [set up data collection](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-3-set-up-data-collection). Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-2-make-the-project-dynamic --- # Set up data collection with tracking *Prepr is a CMS that includes built-in A/B testing and personalization features. These capabilities require visitor data to measure your test results and to build segments for personalization. This chapter of the Nuxt complete guide shows you how to enable tracking to collect this data in your Nuxt front end.* ## Enable Prepr tracking and collect view events The steps below continue from the previous section, [Make your Nuxt project dynamic](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-2-make-the-project-dynamic). If you don't yet have a Nuxt project connected to Prepr, follow the previous steps listed in the [Complete guide overview](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide) to create one. Otherwise, let's get started. Congratulations! You've successfully enabled Prepr tracking in your Nuxt front end, and started collecting page view events. Now, you're ready to [add A/B testing](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-4-add-ab-testing) and [personalization](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-3-set-up-data-collection --- # Add A/B testing to your Nuxt website *Prepr CMS enables editors to create A/B tests directly within their content. This means testing different content versions is simple and effective. This chapter of the Nuxt complete guide demonstrates how to set up A/B testing in Prepr, including testing the display of variants and measuring the results.* At the end of this section, you'll see the A and B versions on the *Electric Lease Landing Page*. ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) The steps below make use of the A/B test in the *Electric Lease Landing Page* content item from the Acme Lease demo data. ![A/B test in Electric lease content item](https://assets-site.prepr.io/6l4bf1thuzjc//ab-test-example-electric-landing-page.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Nuxt project, follow the steps in this section first. Otherwise, let's get started. ## Set up A/B testing for the *Electric Lease Landing Page* You can run an A/B test on parts of a web page to show two different versions of the content to different visitors and compare which variant is more engaging. To show the right variant to the right visitor: - Every visitor gets an ID that resolves to an A or a B variant. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. Congratulations! You have a running A/B test with metrics in your Nuxt website. Now, you can [Add personalization](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-4-add-ab-testing --- # Add personalization to your Nuxt website *Prepr CMS enables editors to create adaptive content directly in their content items to personalize elements of web pages. This makes setting up personalization really simple and effective in increasing engagement and conversions. This chapter of the Nuxt complete guide shows you how to add personalization to your Nuxt website.* At the end of this section, you'll see a personalized home page for visitors interested in electric cars. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) The steps below make use of the Adaptive content in the *Homepage* content item from the Acme Lease demo data. ![Home page content item](https://assets-site.prepr.io/3kzih4y0123a//acme-lease-homepage-adaptive-content-hero-and-feature-sections.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Nuxt project, follow the steps in this section first. Otherwise, let's get started. ## Set up personalization for the home page You can show different personalized versions of the content to different groups (*Segments*) of visitors. To show the right variant to the right visitor: - Every visitor is given an ID that resolves to a segment they belong to. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. Congratulations! You have successfully set up personalization with metrics in your Nuxt website. This brings you to the end of the Nuxt complete guide which has given you all the tools and tips you need to create your own web app connected to Prepr CMS complete with personalization, and A/B testing. Don't hesitate to [give us feedback](mailto:feedback@prepr.io) on your experience using this guide. ## Next steps To learn more on how to expand your project, check out the following resources: - [Set up visual editing](/project-setup/setting-up-visual-editing) - [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/nuxtjs/nuxt-complete-guide/step-5-add-personalization --- # Introduction to the Laravel complete guide *This section introduces you to the complete guide that shows you how to connect Prepr to a Laravel project including styling, adaptive content, A/B testing and the visual editing setup.* At the end of the complete guide, you’ll have a working website with personalization and A/B testing like the images below. You can customize this project to fit the requirements for your web app. **Home page for general website visitors** ![Laravel Dynamic home page](https://assets-site.prepr.io/4nsjg3xg5w9w//laravel-dynamic-site.png) **Two variants of a running A/B test on a landing page** ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) **Personalized home page for electric car lovers** ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) {/* If you can't wait and want to skip ahead, clone the [repository on GitHub](https://github.com/preprio/laravel-complete-starter) to run the demo locally or visit our [demo website](https://acme-lease-v2.vercel.app/en-US) to see it in action. These resources and this guide are based on the latest version of Laravel. */} ## Prerequisites Make sure the following is in place before getting started: - [A free Prepr account](https://signup.prepr.io/?plan=free) - [An environment with Acme Lease demo data in Prepr](/project-setup/setting-up-environments#create-an-environment) Now that you know what to expect and have your Prepr environment ready, you can get started with the first step to [set up the Laravel project](step-1-set-up-a-laravel-project). Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide/introduction --- # Set up a Laravel project *The instructions below will guide you through the first step of the Laravel complete guide. These show you how to create a Laravel website with static components.* ![Laravel site with static components](https://assets-site.prepr.io/5akwi5xsqx21//acme-lease-static-home-page.png) ## Create a Laravel website with static components If you have an existing Laravel project then you can skip this section and continue with the next section to [make your Laravel project dynamic with Prepr content](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-2-make-the-project-dynamic). Otherwise, let's get started. Great work on getting your static web app working! Continue your journey to the next section to [make your Laravel project dynamic with Prepr content](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-2-make-the-project-dynamic). Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-1-set-up-a-laravel-project --- # Make your Laravel project dynamic *This guide shows you how to connect an existing Laravel project to Prepr to retrieve and show Acme Lease demo content.* ## Connect your Laravel website to Prepr The steps below continue from the previous section, [Set up a Laravel project](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-1-set-up-a-laravel-project). If you don't yet have a Laravel website with static pages, follow the steps in this section first. Otherwise, let's get started. Congratulations! You have successfully connected your front end to Prepr to make your website dynamic. Continue your journey to the next section to [set up data collection](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-3-set-up-data-collection). Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-2-make-the-project-dynamic --- # Set up data collection with tracking *Prepr is a CMS that includes built-in A/B testing and personalization features. These capabilities require visitor data to measure your test results and to build segments for personalization. This chapter of the Laravel complete guide shows you how to enable tracking to collect this data in your Laravel front end.* ## Enable Prepr tracking and collect view events The steps below continue from the previous section, [Make your Laravel project dynamic](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-2-make-the-project-dynamic). If you don't yet have a Laravel project connected to Prepr, follow the previous steps listed in the [Complete guide overview](/connecting-a-front-end-framework/laravel/laravel-complete-guide) to create one. Otherwise, let's get started. Congratulations! You've successfully enabled Prepr tracking in your Laravel front end, and started collecting page view events. Now, you're ready to [add A/B testing](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-4-add-ab-testing) and [personalization](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-3-set-up-data-collection --- # Add A/B testing to your Laravel website *Prepr CMS enables editors to create A/B tests directly within their content. This means testing different content versions is simple and effective. This chapter of the Laravel complete guide demonstrates how to set up A/B testing in Prepr, including testing the display of variants and measuring the results.* At the end of this section, you'll see the A and B versions on the *Electric Lease Landing Page*. ![Electric landing page with A/B test](https://assets-site.prepr.io/2u8iwxsr0nls//a-b-test-on-home-page.png) The steps below make use of the A/B test in the *Electric Lease Landing Page* content item from the Acme Lease demo data. ![A/B test in Electric lease content item](https://assets-site.prepr.io/6l4bf1thuzjc//ab-test-example-electric-landing-page.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Laravel project, follow the steps in this section first. Otherwise, let's get started. ## Set up A/B testing for the *Electric Lease Landing Page* You can run an A/B test on parts of a web page to show two different versions of the content to different visitors and compare which variant is more engaging. To show the right variant to the right visitor: - Every visitor gets an ID that resolves to an A or a B variant. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. Congratulations! You have a running A/B test with metrics in your Laravel website. Now, you can [Add personalization](/connecting-a-front-end-framework/nuxtjs/nuxt-complete-guide/step-5-add-personalization) to your website. Source: https://docs.prepr.io/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-4-add-ab-testing --- # Add personalization to your Laravel website *Prepr CMS enables editors to create adaptive content directly in their content items to personalize elements of web pages. This makes setting up personalization really simple and effective in increasing engagement and conversions. This chapter of the Laravel complete guide shows you how to add personalization to your Laravel website.* At the end of this section, you'll see a personalized home page for visitors interested in electric cars. ![Personalized home page](https://assets-site.prepr.io/50el53oh29zt//personalized-home-page-electric-lease.png) The steps below make use of the Adaptive content in the *Homepage* content item from the Acme Lease demo data. ![Home page content item](https://assets-site.prepr.io/3kzih4y0123a//acme-lease-homepage-adaptive-content-hero-and-feature-sections.png) This chapter continues from the previous section, [Set up data collection](/connecting-a-front-end-framework/laravel/laravel-complete-guide/step-3-set-up-data-collection). If you haven't yet enabled Prepr tracking in your Laravel project, follow the steps in this section first. Otherwise, let's get started. ## Set up personalization for the home page You can show different personalized versions of the content to different groups (*Segments*) of visitors. To show the right variant to the right visitor: - Every visitor is given an ID that resolves to a segment they belong to. - In your front end, you need to send this ID along with the query to retrieve the right variant. - This is done by setting the value for the API request header, `Prepr-Customer-Id`, when you make the API request to retrieve the content. Congratulations! You have successfully set up personalization with metrics in your Laravel website. This brings you to the end of the Laravel complete guide which has given you all the tools and tips you need to create your own web app connected to Prepr CMS complete with personalization, and A/B testing. Don't hesitate to [give us feedback](mailto:feedback@prepr.io) on your experience using this guide. ## Next steps To learn more on how to expand your project, check out the following resources: - [Set up visual editing](/project-setup/setting-up-visual-editing) - [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/laravel/laravel-complete-guide/step-5-add-personalization --- # Images *This guide describes how to add images to your web application using Prepr. Follow the step-by-step instructions to master the process.* ## Introduction It’s hard to imagine today’s content delivery without images. Whatever copy you see on the internet — a webinar schedule, a product description, a blog post, a daily news feed, etc. — they all have visuals to attract and engage customers. Using image files has become a routine task for content editors. With Prepr, you can do that in a quick and simple way. Additionally, working with various image formats and automatic image optimization is as easy as it gets. Imagine you’re creating a blog post and want to support it with images. In this case, you will go through the following steps in Prepr: - First, allow using assets in a model. - Next, add images to a content item. - Optionally, edit and configure images. - Finally, retrieve images using the API. Let’s begin. ## Step 1: Add an Assets field to your model To use assets in your content items, you must first add the Assets field to a content model as follows: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click on a model to open its details. 3. Click or drag the *Assets* field from the list of field types into your model. ![Add Assets field](https://assets-site.prepr.io/w_1920/iva7efxy2m3-01-add-assets-field.png) 4. Fill in the *Assets* field settings, then click **Save** to confirm. For more information, check out the [Field types guide](/content-modeling/field-types#assets-field). ![Fill in Assets field settings](https://assets-site.prepr.io/w_1920/4ub8yiingure-02-assets-field-settings-image.png) Once done, you can add images to your content item. ## Step 2: Add images to a content item Now that you have allowed using assets in a model, you can add images to your content item as follows: 1. Navigate to the **Content** tab. You can either [create a new content item](/content-management/managing-content/managing-content-items#create-a-content-item) or use an existing one. 2. On the **Content item** page, go to the media placeholder and click the icon. ![Add asset to a content item](https://assets-site.prepr.io/w_1920/6soir3gcjf0a-03-add-asset-to-a-content-item.png) 3. Select one or multiple images from the Media Library or upload new ones. 4. Click **Add x items** to confirm. ![Select asset](https://assets-site.prepr.io/w_1920/41k95ljuiy2i-04-select-asset-image.png) ## Step 3 (optional): Edit and configure images Once you’ve added images to your content item, Prepr gives you various options to enhance your image files. In the *Prepr Editor* interface, you can perform the following actions: - [Crop images](/content-management/managing-assets/editing-and-configuring-assets#cropping-images) based on your image presets to adjust visuals to a specific device type or web page element. - [Add a caption](/content-management/managing-assets/editing-and-configuring-assets#adding-captions) to provide a comprehensive description of your images. If you run a multi-language application, you can easily [localize image captions](/content-management/localizing-content#manage-captions-in-multi-language-content-items). - [Set alignment](/content-management/managing-assets/editing-and-configuring-assets#setting-alignment) to define the position on a web page. On the **Content item** page, hover over an image and click the icon in the top right corner, then select the needed action. ![Edit image](https://assets-site.prepr.io/w_1920/75p0gdp91zo9-edit-image.png) Alternatively, you can transform images on the fly using the API. For more details, check out the following references: - [REST API](/mutation-api/assets-resizing) - [GraphQL API](/graphql-api/schema-field-types#images) Once done, proceed to the next step. ## Step 4: Retrieve images using the API Now that you've added and configured images, you can retrieve these files using the API. The following snippet shows how to retrieve image files, including image presets named *"desktop"* and *"mobile"*, image caption, alignment, and author. You may want to add or remove arguments according to your desired set-up. For more information, see the [GraphQL API reference](/graphql-api/schema-field-types#assets). That's it. Once you [publish your content item](/content-management/managing-content/managing-content-items#publish-a-content-item), images become available in your web application in the best possible format. ## Want to learn more? Check out the following guides to learn how to add other asset types to your web application: - [Video & Audio](/development/best-practices/assets/video-audio) - [Live video stream](/development/best-practices/assets/live-video-stream) - [Files](/development/best-practices/assets/files) Source: https://docs.prepr.io/development/best-practices/assets/images --- # Video and Audio *Follow this guide to learn how to add video and audio files to your web application using Prepr.* ## Introduction Video and audio have become one of the most popular ways that people consume content. You can use video and audio in a variety of ways: from brand videos to instructional videos to audiobooks and news reports, and many more. Whatever goal you have, Prepr will help you embed your video/audio files in a web application with ease. All the video and audio files uploaded to Prepr are stored in and played from Mux. You can read more about the Prepr and Mux integration in our blog post. To play video/audio in a web application, you need to complete the following steps: 1. First, allow using assets in a model. 2. Next, add a video/audio file to a content item. 3. Then, add a web player to your front end. 4. Finally, retrieve a video/audio file using the API. See the detailed instructions below. ## Step 1: Add an Assets field to your model To use assets in your content items, you must first add the Assets field to a content model as follows: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click on a model to open its details. 3. Click or drag the *Assets* field from the list of field types into your model. ![Add Assets field](https://assets-site.prepr.io/w_1920/iva7efxy2m3-01-add-assets-field.png) 4. Fill in the *Assets* field settings, then click **Save** to confirm. For more information, check out the [Field types guide](/content-modeling/field-types#assets-field). ![Fill in Assets field settings](https://assets-site.prepr.io/w_1920/7giqe6oo103e-02-assets-field-settings-video-audio.png) Once done, you can add a video/audio file to your content item. ## Step 2: Add a file to a content item Now that you have allowed using assets in a model, you can add video/audio to your content item as follows: 1. Navigate to the **Content** tab. You can either [create a new content item](/content-management/managing-content/managing-content-items#create-a-content-item) or use an existing one. 2. On the **Content item** page, go to the media placeholder and click the icon. ![Add asset to a content item](https://assets-site.prepr.io/w_1920/6soir3gcjf0a-03-add-asset-to-a-content-item.png) 3. Select one or multiple video/audio files from the Media Library or upload new ones. 4. Click **Add x items** to confirm. ![Select asset](https://assets-site.prepr.io/w_1920/60ox33n6hhx6-04-select-asset-video-audio.png) Optionally, you can edit your video/audio in the *Prepr Editor* interface as follows: - [Add a caption](/content-management/managing-assets/editing-and-configuring-assets#adding-captions) to describe your video/audio file. If you run a multi-language application, you can easily [localize image captions](/content-management/localizing-content#manage-captions-in-multi-language-content-items). - [Set alignment](/content-management/managing-assets/editing-and-configuring-assets#setting-alignment) to define the position of a video/audio file on a web page. On the **Content item** page, hover over a video/audio file and click the icon in the top right corner, then select the needed action. ![Configure asset](https://assets-site.prepr.io/w_1920/60r9syq7e9qx-configure-asset.png) Once done, proceed to the next step. ## Step 3: Add a web player to your front end Now that you’ve prepared a video/audio file for displaying, you can choose which web player to use in your web application. Because Mux delivers your videos in the *HTTP Live Streaming (HLS)* format, we recommend using a player that supports HLS. Here are some popular players you may want to use: - [Mux Player](https://docs.mux.com/guides/mux-player-web) is a native player developed by Mux. - [HLS.js](https://github.com/video-dev/hls.js) is free and open source. HLS.js will be a good choice if you want to use the HTML5 video element's default controls or build your own UI elements. - [Agnoplay](https://www.agnoplay.com/) is a fully agnostic, cloud-based player solution for web, iOS, and Android. - [JWPlayer](https://www.jwplayer.com/html5-video-player/) is a commercial player that supports HLS by default and uses HLS.js as an underlying HLS engine. Check out other options in the [Mux documentation](https://docs.mux.com/guides/play-your-videos#popular-web-players). ## Step 4: Retrieve video/audio using the API Once you have completed the previous steps, you can retrieve your video/audio file using the API to integrate with a web player. Use the following snippets as a starting point to retrieve your live stream via the API. You may want to add or remove arguments according to your desired setup. For more information, see the [GraphQL API reference](/graphql-api/schema-field-types#video). Fo more details on customizing the thumbnail for your Mux video, check out [the Mux docs](https://docs.mux.com/guides/player-customize-look-and-feel#customize-the-poster-image). That's it. Once you [publish your content item](/content-management/managing-content/managing-content-items#publish-a-content-item), your video and audio file become available in your web application in the best possible format. ## Want to learn more? Check out the following guides to learn how to add other asset types to your web application: - [Live video stream](/development/best-practices/assets/live-video-stream) - [Images](/development/best-practices/assets/images) - [Files](/development/best-practices/assets/files) Source: https://docs.prepr.io/development/best-practices/assets/video-audio --- # Live video stream *Follow this guide to learn how to add a live video stream to your web application using Prepr.* ## Introduction Imagine you are about to hold a corporate event. In this case, you may want to create a web page to announce and broadcast your virtual event. Also, recording your online event might be essential, especially if you attract attendees located in another time zone or want to send out the replay to all registrants. Prepr makes all this incredibly simple with the *Live streaming* feature powered by Mux's advanced video services. Prepr works as a centralized interface you can use for the following purposes: - Create and manage a live video stream. - Integrate a live video stream in a web application using the API and a video player. - Save and store your live stream as an on-demand video recording. This article will guide you through the steps needed to build and launch your online event with Prepr: 1. Set up a live stream in Prepr. 2. Configure your broadcast software. 3. Add a web player to your front end. 4. Integrate your live stream with the web player. 5. Play your live stream. Let’s dive in. ## Step 1: Set up a live stream in Prepr To set up a live stream in Prepr, you need to complete the following actions: 1. **Create a model with the Assets field.** Let’s create a sample blog article you can use to broadcast your live video stream in a web application. To do it, complete the following actions: a. Click the **Schema** tab to open the *Schema Editor*. Then, click the **+ Add model** button. Follow the interface tips to tailor your model. b. Click or drag fields from the Field types list into your model. Use the following field names and types: - *Heading - Text* - *Live stream - Assets* - *Content - Dynamic content* ![Add Assets field](https://assets-site.prepr.io//3frnw0q8j4zo-01-add-assets-field.png) c. Fill in the field settings, then click **Save** to confirm. For more information, check out all available [Field types](/content-modeling/field-types). ![Fill in Assets field settings](https://assets-site.prepr.io//7c5rfd0m6qr1-01-assets-field-settings-video.png) 2. **Create a livestream asset.** Now you need to create a live stream asset in Prepr. See the details below. a. Go to the **Media** tab and click **Upload assets → drop-down menu > Add live stream**. ![Add a live stream](https://assets-site.prepr.io//4ghu6d4ho8s6-02-create-live-stream.png) b. In the pop-up dialog window, give your live stream asset a name and click **Add** to confirm and generate a unique stream key for your broadcast. ![Confirm a live stream creation](https://assets-site.prepr.io//1skjqaysg99k-03-live-stream-dialog-1.png) c. The next screen gives you the *Server URL* and *Stream key* that you need to [connect to the broadcast software](/development/best-practices/assets/live-video-stream#step-2-configure-your-broadcast-software): - *Server URL* is the URL of the Mux RTMP server used to connect your broadcast software to Mux’s entry point for live streams. - *Stream key* is your secret key used to authenticate your live stream with the Mux RTMP server in your broadcast software. ![Live stream details](https://assets-site.prepr.io//3y5gjz9q49nl-04-live-stream-dialog-2.png) Once done, you can add the live stream asset to a content item. 3. **Add a live stream asset to a content item.** Now that you have created the live stream asset, you can add it to your content item as follows: a. Navigate to the **Content** tab. You can either [create a new content item](/content-management/managing-content/managing-content-items#create-a-content-item) or use an existing one. b. On the **Content item** page, go to the *Live stream* field and click the icon. ![Add live stream asset](https://assets-site.prepr.io//60lu4xgftl1l-05-add-live-stream-asset.png) c. Select the live stream asset you created in the previous step from the Media Library and click **Add 1 item** to confirm. ![Select asset](https://assets-site.prepr.io//5ulj4pksrv6e-05-add-live-stream-asset-media-library.png) 4. **Publish your content item.** To make your content available in a web application, click the **Publish and close** button. For more details, see [Publishing content items](/content-management/managing-content/managing-content-items#publish-a-content-item). ![Publish content item](https://assets-site.prepr.io//25095979nuyi-06-publish-content-item.png) Once done, proceed to the next step. ## Step 2: Configure your broadcast software Now that you’ve set up the live stream in Prepr, you can move forward. In this step, you need to configure your broadcast software using the Stream key you copied from the previous step and the Server URL. Broadcast software uses video encoding technology to convert your video feed into a digital format suitable for live streaming across various devices and platforms. Here’s the list of broadcast solutions you may want to consider: - [OBS](https://obsproject.com/) (free and open source, macOS/Windows/Linux) - [Wirecast](https://www.telestream.net/wirecast/) (commercial, macOS/Windows) - [Larix Broadcaster](https://apps.apple.com/us/app/larix-broadcaster/id1042474385) (free, iOS) - [Wirecast Go](https://apps.apple.com/us/app/wirecast-go/id987286934) (commercial, iOS) Let’s go with OBS as an example. Configure a Custom streaming server by filling in the Server URL and entering your Stream key. Check out the [OBS documentation](https://obsproject.com/wiki/OBS-Studio-Overview) for more tips. ![Configure your broadcast software](https://assets-site.prepr.io/w_1920/4aqejqwjkx9c-configure-broadcast-software.png) Once done, navigate to the next step. ## Step 3: Add a web player to your front end Now that you’ve prepared a live stream asset and configured your broadcast software, you can choose which web player to use in your web application. Because Mux delivers your videos in the *HTTP Live Streaming (HLS)* format, we recommend using a player that supports HLS. Here are some popular players you may want to use: - [Mux Player](https://docs.mux.com/guides/mux-player-web) is a native player developed by Mux. - [HLS.js](https://github.com/video-dev/hls.js) is free and open source. HLS.js will be a good choice if you want to use the HTML5 video element's default controls or build your own UI elements. - [Agnoplay](https://www.agnoplay.com/) is a fully agnostic, cloud-based player solution for web, iOS, and Android. - [JWPlayer](https://www.jwplayer.com/html5-video-player/) is a commercial player that supports HLS by default and uses HLS.js as an underlying HLS engine. Check out other options in the [Mux documentation](https://docs.mux.com/guides/play-your-videos#popular-web-players). ## Step 4: Integrate your live stream with the web player Once you’ve completed the previous steps, you can integrate your live stream with the web player using a video Playback ID. Use the following snippets as a starting point to retrieve your live stream via the API. You may want to add or remove arguments according to your desired setup. For more information, see the [GraphQL API reference](/graphql-api/schema-field-types#video). Once done, copy and paste the live stream details returned in the API response to your web player. ## Step 5. Play your live stream Follow your broadcast software instructions to learn how to play a live stream. Some general recommendations are listed below. **Start a live stream** Once the live stream begins, it becomes available in your web application instantly. At the same time, the software starts pushing live video to the video host server. ![Start streaming](https://assets-site.prepr.io/w_1920/6329av8ziyi-screenshot-2022-10-05-at-123729.png) You can also see the *Live* label in the live stream asset in Prepr: ![Live stream asset in Prepr](https://assets-site.prepr.io//7964025jvvhu-07-go-live.png) **Stop a live stream** Refer to your broadcast software documentation on how to stop a live stream. Please note there may be a slight delay between when you stop streaming in the broadcast software and when the recording stops in Prepr. To stop recording immediately, we recommend that you follow this sequence of actions: 1. First, stop recording your live stream in Prepr. For that, go to the **Media** tab and open the live stream asset. On the **Live stream asset** page, click **Finish live stream**. ![Stop streaming](https://assets-site.prepr.io//2ifpaeez1usl-08-stop-streaming.png) 2. Then, stop streaming in your broadcast software. Once done, the live stream will be replaced with the video recording in your web application automatically. Alternatively, you can access and play this video recording in the Media Library. Because Prepr keeps your Stream key active, the live stream asset also remains available in the Media Library. So you can start a new live stream using the same credentials anytime. In this case, you’ll get several video recordings of your live stream in the Media Library, and your web page will show the latest recording every time. ![Live strem recording in Media Library](https://assets-site.prepr.io//19g4krz22wqk-09-recording.png) ## Want to learn more? Check out the following guides to learn how to add other asset types to your web application: - [Images](/development/best-practices/assets/images) - [Video & Audio](/development/best-practices/assets/video-audio) - [Files](/development/best-practices/assets/files) Source: https://docs.prepr.io/development/best-practices/assets/live-video-stream --- # Files *This guide describes adding different file formats such as PDF, ZIP, GIF, and more to your web application using Prepr.* ## Introduction Prepr allows you to add several file formats to a web application. You can use popular file types like PDF and ZIP, for example, to publish a Press kit, Terms of use, or any other document you want your website visitors to download. To add a file to a web application, you need to complete the following steps: 1. First, allow using assets in a model. 2. Next, add a file to a content item. 3. Finally, retrieve a file using the API. See the detailed instructions below. ## Step 1: Add an Assets field to your model To use assets in your content items, you must first add the Assets field to a content model as follows: 1. Click the **Schema** tab to open the *Schema Editor*. 2. Click on a model to open its details. 3. Click or drag the *Assets* field from the list of field types into your model. ![Add Assets field](https://assets-site.prepr.io/w_1920/iva7efxy2m3-01-add-assets-field.png) 4. Fill in the *Assets* field settings, then click **Save** to confirm. For more information, check out the [Field types guide](/content-modeling/field-types#assets-field). ![Fill in Assets field settings](https://assets-site.prepr.io/w_1920/4n8132wi1are-02-assets-field-settings-file.png) Once done, you can add a file to your content item. ## Step 2: Add a file to a content item Now that you have allowed using assets in a model, you can add a file to your content item as follows: 1. Navigate to the **Content** tab. You can either [create a new content item](/content-management/managing-content/managing-content-items#create-a-content-item) or use an existing one. 2. On the **Content item** page, go to the media placeholder and click the icon. ![Add asset to a content item](https://assets-site.prepr.io/w_1920/6soir3gcjf0a-03-add-asset-to-a-content-item.png) 3. Select one or multiple images from the Media Library or upload new ones. 4. Click **Add x items** to confirm. ![Select asset](https://assets-site.prepr.io/w_1920/483031r25bei-04-select-asset-file.png) Optionally, you can edit a file in the *Prepr Editor* interface as follows: - [Add a caption](/content-management/managing-assets/editing-and-configuring-assets#adding-captions) to provide additional information about your file. If you run a multi-language application, you can easily [localize image captions](/content-management/localizing-content#manage-captions-in-multi-language-content-items). - [Set alignment](/content-management/managing-assets/editing-and-configuring-assets#setting-alignment) to define the position of a file on a web page. On the **Content item** page, hover over a file and click the icon in the top right corner, then select the needed action. ![Configure asset](https://assets-site.prepr.io/w_1920/60r9syq7e9qx-configure-asset.png) Once done, proceed to the next step. ## Step 3: Retrieve a file using the API Once you have completed the previous steps, you can retrieve your file using the API. Use the following snippets as a starting point to retrieve an identifier, a URL and the type of your file. You may want to add or remove arguments according to your desired set-up. For more information, see the [GraphQL API reference](/graphql-api/schema-field-types#assets). That's it. Once you [publish your content item](/content-management/managing-content/managing-content-items#publish-a-content-item), your file becomes available in your web application for download. ## Want to learn more? Check out the following guides to learn how to add other asset types to your web application: - [Images](/development/best-practices/assets/images) - [Video & Audio](/development/best-practices/assets/video-audio) - [Live video stream](/development/best-practices/assets/live-video-stream) Source: https://docs.prepr.io/development/best-practices/assets/files