Skip navigation

Set up preview for content items

Learn how to set up content preview for your Kontent project. This will involve adjusting your app so that it retrieves latest content when needed. Then you'll set up environments for your app and make your app recognize them. And finally, you'll make a few changes in your project so that Kontent knows which preview pages to open for which content types and items. 

At the end, you'll have preview URLs for each type of preview-able content, like articles or a home page. Doing all this lets your writers preview unpublished content and review it with confidence. Let's begin!

Table of contents

    Get the latest version of everything

    Start with teaching your app how to fetch the latest versions of your content. You do that by making requests to the Delivery Preview API. Every request to the API must be authenticated with an API key and there are two keys, Primary and Secondary.

    Primary vs. Secondary key

    The following instructions work equally for both the Primary key and the Secondary key. Both API keys are generated per project and have no expiration date. For continuous use, we recommend using the Primary key. Use the Secondary key only when revoking the Primary key to prevent downtime.

    To get the Preview API key:

    1. In Kentico Kontent, choose your project.
    2. From the app menu, choose .
    3. Under Environment settings, choose API keys.
    4. In the Preview API box, click .

    Use the key in your app to authenticate your requests to the Preview API. For example, this is how you can get the latest version of a My article item.

    • Java
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/javaandroid import com.github.kentico.kontent_delivery_core.*; import com.github.kentico.kontent_delivery_rx.*; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; // Prepares an array to hold strongly-typed models List<TypeResolver<?>> typeResolvers = new ArrayList<>(); // Registers the type resolver for articles typeResolvers.add(new TypeResolver<>(Article.TYPE, new Function<Void, Article>() { @Override public Article apply(Void input) { return new Article(); } })); // Prepares the DeliveryService configuration object String projectId = "<YOUR_PROJECT_ID>"; String previewApiKey = "<YOUR_PREVIEW_API_KEY>"; IDeliveryConfig config = DeliveryConfig.newConfig(projectId) .withTypeResolvers(typeResolvers) .withPreviewApiKey(previewApiKey); // Initializes a DeliveryService for Java projects IDeliveryService deliveryService = new DeliveryService(config); // Gets the latest version of a content item using a simple request Article item = deliveryService.<Article>item("my_article") .get() .getItem(); // Gets the latest version of a content item using RxJava2 deliveryService.<Article>item("my_article") .getObservable() .subscribe(new Observer<DeliveryItemResponse<Article>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(DeliveryItemResponse<Article> response) { // Gets the article Article item = response.getItem(); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/javaandroid import com.github.kentico.kontent_delivery_core.*; import com.github.kentico.kontent_delivery_rx.*; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; // Prepares an array to hold strongly-typed models List<TypeResolver<?>> typeResolvers = new ArrayList<>(); // Registers the type resolver for articles typeResolvers.add(new TypeResolver<>(Article.TYPE, new Function<Void, Article>() { @Override public Article apply(Void input) { return new Article(); } })); // Prepares the DeliveryService configuration object String projectId = "<YOUR_PROJECT_ID>"; String previewApiKey = "<YOUR_PREVIEW_API_KEY>"; IDeliveryConfig config = DeliveryConfig.newConfig(projectId) .withTypeResolvers(typeResolvers) .withPreviewApiKey(previewApiKey); // Initializes a DeliveryService for Java projects IDeliveryService deliveryService = new DeliveryService(config); // Gets the latest version of a content item using a simple request Article item = deliveryService.<Article>item("my_article") .get() .getItem(); // Gets the latest version of a content item using RxJava2 deliveryService.<Article>item("my_article") .getObservable() .subscribe(new Observer<DeliveryItemResponse<Article>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(DeliveryItemResponse<Article> response) { // Gets the article Article item = response.getItem(); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
    • Swift
    // Tip: Find more about Swift SDK at https://docs.kontent.ai/ios import KenticoKontentDelivery let client = DeliveryClient.init(projectId: "<YOUR_PROJECT_ID>", apiKey: "<YOUR_PREVIEW_API_KEY>") // More about strongly-typed models https://github.com/Kentico/kontent-delivery-sdk-swift#using-strongly-typed-models client.getItem(modelType: Article.self, itemName: "my_article") { (isSuccess, itemResponse, error) in if isSuccess { if let article = itemResponse.item { // Use your item here } } else { if let error = error { print(error) } } }
    // Tip: Find more about Swift SDK at https://docs.kontent.ai/ios import KenticoKontentDelivery let client = DeliveryClient.init(projectId: "<YOUR_PROJECT_ID>", apiKey: "<YOUR_PREVIEW_API_KEY>") // More about strongly-typed models https://github.com/Kentico/kontent-delivery-sdk-swift#using-strongly-typed-models client.getItem(modelType: Article.self, itemName: "my_article") { (isSuccess, itemResponse, error) in if isSuccess { if let article = itemResponse.item { // Use your item here } } else { if let error = error { print(error) } } }
    • Java
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/java import com.github.kentico.kontent.delivery; DeliveryClient client = new DeliveryClient("<YOUR_PROJECT_ID>", "<YOUR_PREVIEW_API_KEY>"); ContentItem item = client.getItem("my_article").item;
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/java import com.github.kentico.kontent.delivery; DeliveryClient client = new DeliveryClient("<YOUR_PROJECT_ID>", "<YOUR_PREVIEW_API_KEY>"); ContentItem item = client.getItem("my_article").item;
    • JavaScript
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript const KontentDelivery = require('@kentico/kontent-delivery'); const deliveryClient = new KontentDelivery.DeliveryClient({ projectId: '<YOUR_PROJECT_ID>', previewApiKey: '<YOUR_PREVIEW_API_KEY>', globalQueryConfig: { usePreviewMode: true, // Queries the Delivery Preview API. }, typeResolvers: [ // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models new KontentDelivery.TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item('my_article') .toObservable() .subscribe(response => console.log(response));
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript const KontentDelivery = require('@kentico/kontent-delivery'); const deliveryClient = new KontentDelivery.DeliveryClient({ projectId: '<YOUR_PROJECT_ID>', previewApiKey: '<YOUR_PREVIEW_API_KEY>', globalQueryConfig: { usePreviewMode: true, // Queries the Delivery Preview API. }, typeResolvers: [ // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models new KontentDelivery.TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item('my_article') .toObservable() .subscribe(response => console.log(response));
    • C#
    // Tip: Find more about .NET SDKs at https://docs.kontent.ai/net using Kentico.Kontent.Delivery; // Creates an instance of the delivery client // ProTip: Use DI for this in your apps https://docs.kontent.ai/net-register-client for previewing content IDeliveryClient client = DeliveryClientBuilder .WithOptions(builder => builder .WithProjectId("975bf280-fd91-488c-994c-2f04416e5ee3") .UsePreviewApi("<YOUR_PREVIEW_API_KEY>") .Build()) .Build(); // Gets the latest version of a content item // Create strongly typed models according to https://docs.kontent.ai/net-strong-types DeliveryItemResponse<Article> response = await client.GetItemAsync<Article>("my_article"); Article item = response.Item;
    // Tip: Find more about .NET SDKs at https://docs.kontent.ai/net using Kentico.Kontent.Delivery; // Creates an instance of the delivery client // ProTip: Use DI for this in your apps https://docs.kontent.ai/net-register-client for previewing content IDeliveryClient client = DeliveryClientBuilder .WithOptions(builder => builder .WithProjectId("975bf280-fd91-488c-994c-2f04416e5ee3") .UsePreviewApi("<YOUR_PREVIEW_API_KEY>") .Build()) .Build(); // Gets the latest version of a content item // Create strongly typed models according to https://docs.kontent.ai/net-strong-types DeliveryItemResponse<Article> response = await client.GetItemAsync<Article>("my_article"); Article item = response.Item;
    • PHP
    // Tip: Find more about PHP SDKs at https://docs.kontent.ai/php // Defined by Composer to include required libraries require __DIR__ . '/vendor/autoload.php'; use Kentico\Kontent\Delivery\DeliveryClient; $client = new DeliveryClient('<YOUR_PROJECT_ID>', '<YOUR_PREVIEW_API_KEY>'); $item = $client->getItem('my_article');
    // Tip: Find more about PHP SDKs at https://docs.kontent.ai/php // Defined by Composer to include required libraries require __DIR__ . '/vendor/autoload.php'; use Kentico\Kontent\Delivery\DeliveryClient; $client = new DeliveryClient('<YOUR_PROJECT_ID>', '<YOUR_PREVIEW_API_KEY>'); $item = $client->getItem('my_article');
    • cURL
    curl --request GET \ --url https://preview-deliver.kontent.ai/<YOUR_PROJECT_ID>/items/my_article \ --header 'authorization: Bearer <YOUR_PREVIEW_API_KEY>'
    curl --request GET \ --url https://preview-deliver.kontent.ai/<YOUR_PROJECT_ID>/items/my_article \ --header 'authorization: Bearer <YOUR_PREVIEW_API_KEY>'
    • Ruby
    # Tip: Find more about Ruby SDKs at https://docs.kontent.ai/ruby require 'delivery-sdk-ruby' delivery_client = Kentico::Kontent::Delivery::DeliveryClient.new project_id: '975bf280-fd91-488c-994c-2f04416e5ee3', preview_key: '<YOUR_PREVIEW_API_KEY>' delivery_client.item('my_article').execute do |response| item = response.item end
    # Tip: Find more about Ruby SDKs at https://docs.kontent.ai/ruby require 'delivery-sdk-ruby' delivery_client = Kentico::Kontent::Delivery::DeliveryClient.new project_id: '975bf280-fd91-488c-994c-2f04416e5ee3', preview_key: '<YOUR_PREVIEW_API_KEY>' delivery_client.item('my_article').execute do |response| item = response.item end
    • TypeScript
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript import { ContentItem, DeliveryClient, Elements, TypeResolver } from '@kentico/kontent-delivery'; import { Article } from './models/Article'; const deliveryClient = new DeliveryClient({ projectId: '<YOUR_PROJECT_ID>', previewApiKey: '<YOUR_PREVIEW_API_KEY>', globalQueryConfig: { usePreviewMode: true, // Queries the Delivery Preview API. }, typeResolvers: [ // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models new TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item<Article>('my_article') .toObservable() .subscribe(response => console.log(response));
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript import { ContentItem, DeliveryClient, Elements, TypeResolver } from '@kentico/kontent-delivery'; import { Article } from './models/Article'; const deliveryClient = new DeliveryClient({ projectId: '<YOUR_PROJECT_ID>', previewApiKey: '<YOUR_PREVIEW_API_KEY>', globalQueryConfig: { usePreviewMode: true, // Queries the Delivery Preview API. }, typeResolvers: [ // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models new TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item<Article>('my_article') .toObservable() .subscribe(response => console.log(response));

    Set up environments for your app

    Assuming your app can correctly display the content it gets from a Kontent project, your next step is ensuring that your app runs in two separate environments. Let's call them production and preview. In the production environment, your app gets and displays only the published content. In the preview environment, your app gets and displays the latest versions of your published and unpublished content.

    The main difference between the two environments will be the environment variables available to your app. In the production environment, you might specify a variable like SecureAccessKey (if you're using secure access), which lets your app see if it's running in a production environment. In such case, the app fetches published content via the Delivery API. For the preview environment, you might specify a variable like PreviewApiKey, which lets your app see if it's running in a preview environment. In this case, the app will fetch both published and unpublished content via the Delivery Preview API. When it comes to getting the content itself, both versions of the Delivery API work the same.

    The way to check the environment variables depends on your tech stack and the service you use to deploy your app. For example, your application can check whether it's running in a preview environment, set a boolean flag based on the check, and use the Delivery (Preview) API as a result. With the Delivery SDKs, the API to use is usually determined by providing or omitting the Preview API key. Keep in mind that server-side technology is required to keep your API keys secret.

    Need to update your project structure?

    If you use only the production and preview environments for your app, any content model change (think content types or taxonomies) to your project will affect both deployment environments. If you want to introduce new models or change your existing models, we recommend using multiple project environments.

    Set up content preview in your project

    Once you've got your app running in a preview environment, you need to specify where (URL-wise) each type of your content can be accessed and viewed. For example, imagine your app runs at https://preview.example.com and you want to set up preview for articles and the home page.

    Each article has its own URL identifier. In Kontent, this identifier is called a URL slug and there's a content type element of the same name. The URL slug element contains a SEO-friendly text usually generated from the article's title. For the home page, however, you don't need a URL slug because the home page sits at the root of your site.

    To set up preview URLs for your project:

    1. In Kentico Kontent, choose from the app menu.
    2. Under Environment settings, choose Preview URLs.
    3. Type in the preview URLs for each type of preview-able content.
    A screenshot of Kontent project settings showing Preview URLs.

    Let's take a closer look at that last step. The preview URLs you provide must be absolute and in this format protocol://domain/path.

    See how to configure previews inside Kentico KontentOpens in a new window.

    Preview URL for articles

    The URL slug of articles is dynamic (each article is titled differently) and you need to reflect that in the preview URL. To do that, use the {URLslug} macro in your preview URL like this https://preview.example.com/articles/{URLslug}.

    If you're not using URL slugs in your content items, you can also use the {Codename} or {ItemId} macros in your preview URLs. The {Codename} macro translates to the codename of a content item and the {ItemId} macro resolves to the internal ID of a content item.

    In multilingual projects, you can use the {Lang} macro in your preview URLs. The {Lang} macro translates to the codename of the currently selected language (such as en-us or es-es) in your Kontent project.

    All of the previously mentioned macros can be used together. For example, when you combine the {URLSlug} and {Lang} macros, you can create preview URLs such as https://preview.example.com/{Lang}/articles/{URLslug} that might resolve to https://preview.example.com/es-es/articles/en-asados.

    Multiple content items can have the same URL slug

    Kentico Kontent doesn't check if the URL slug values in your content items are unique across your project. This means you can have multiple content items with the same URL slug value.

    Preview URLs for the home page

    The home page doesn't need a URL slug because it's static (it's unique and in one location). For example, a home page preview URL of an app running at https://preview.example.com would be https://preview.example.com.

    Set up edit buttons in your preview environment

    Once you have a preview working in both your app and project, it's a good idea to add an Edit button to the preview environment of your application. For your content contributors, this small addition means they can go directly back to editing their texts right from the preview. This will help them in cases they need to fix minor errors or typos right after they spot them when previewing their changes.

    To navigate to an element within a specific item in Kentico Kontent, construct a link with the following structure in your app:

    https://app.kontent.ai/goto/edit-item/project/<YOUR_PROJECT_ID>/variant-codename/<LANGUAGE_CODENAME>/item/<ITEM_ID>/element/<ELEMENT_CODENAME>

    To link to the content item in general, just remove /element/<ELEMENT_CODENAME>. To do more with edit links, like creating links that point to specific elements, see our guide on editing links directly in your app.

    If your editors have problems opening items through the edit links, verify their user roles.

    What's next?