Pages are the most essential components of our platform, that define content displayed at a given path. All pages have to be located in the
views/pages directory. Each page is represented by a single file with
Each page is accessible on the URL indicated by its location in the codebase if not otherwise specified in the page configuration
slug property. For example, the page
app/views/pages/get-started/hello-world.html.liquid deployed to the domain
https://example.com will be automatically accessible at
In examples, we often add the
slug property to show where the page will be accessible, even if it would not be required because it is the same as the default.
Due to the SEO best practices, we automatically replace underscore with dash, so both
hello_world.liquid would evaluate to
hello-world. In such scenario, the one that is updated as the last one will be used.
All page configuration is optional, but you can use page configuration to overwrite defaults.
A sample page configuration file:
--- layout: my_custom_layout converter: markdown ---
# Welcome to My Page A paragraph explaining what I do.
layout: my_custom_layout: The page uses the layout
converter: markdown: It converts markdown in the body of the page to HTML.
|authorization_policies||Array of authorization policies run before rendering the page||No|
|layout||Defines which layout from
If you don't want to use any layout, set it to an empty string. It will be equivalent to just rendering page content.
Note: Currently, excluding this property altogether will cause the page to use the layout last used for the current page. If no layout has been used, it will use the default
|max_deep_level||Defines what is the intended nesting level of the slug. For example, if the slug is
|metadata||Object that you can define and access via
|redirect_code||Status that should be added to http response||301
|redirect_to||URL to a page you want to redirect||No|
|response_headers||JSON object that you can define to override most of the http headers||No|
||The default slug is automatically created based on the page's location in the codebase. For example, a page
Everything after the front matter is the body of the page.
The Homepage slug is
/, which will work for both https://example.com and https://example.com/. The slug of the file
app/views/pages/index.html.liquid defaults to
/. This sample file configures the home page:
<h1>Welcome to my home page</h1> <p>A paragraph explaining what we do</p>
To define which format the endpoint will be available for, place
.<format> before the file extension.
|Format name||Example filename|
Accessing different formats
You can have multiple pages with the same slug, but with different formats, and access them at the same time.
For example, you can have both
txt version of a page with
Will be accessible under URL:
Will be accessible under the URL:
Will be accessible under the URL:
Note that the
html format is implicit, default, you don't need to specify it in the URL or the file name.
To define to which method the endpoint will respond, define
method in the Page configuration. One page can respond to exactly one method.
POST/PUT/PATCH/DELETE methods and Cross-Site Request Forgery attacks
Cross-Site Request Forgety allows attacker to trick an user to execute endpoint without his knowledge. We prevent Cross-Site Request Forgery (CSRF) attacks by requiring CSRF Token to be provided for every request to a Page which is not GET. If the token is missing, then
context.current_user would appear as null, because the user session will be invalidated. To be able to access
context.current_user, you need to provide valid CSRF Token. For Forms we handle it automatically by adding a hidden parameter with name
authenticity_token. However, if you manually trigger a POST/PUT/PATCH/DELETE AJAX request, you need to remember about populating
X-CSRF-Token header with value from
context.authenticity_token and also specify
X-Requested-With: XMLHttpRequest header. Common practice is to include a
meta tag in the layout, for example
<meta content="SiOPe09D8hhgP7hbMT5j8gIKPqyER/bFoU2m4cXxyHt7B83J2jBYy/3isE71ZVpTCmI+Iow5K3l4ENlTk6eZGQ==" name="csrf-token"> and use this value to execute AJAX request.
If you are building JSON API, for example for a mobile app, you might want to authenticate users using JWT tokens.