Advanced features

These are advanced features that are mostly unsupported in oTree Studio.



If the template needs to have a different name from your page class (e.g. you are sharing the same template for multiple pages), set template_name. Example:

class Page1(Page):
    template_name = 'app_name/MyPage.html'

CSS/JS and base templates

To include the same JS/CSS in all pages of an app, either put it in a ref:static file <staticfiles> or put it in an includable template.

Static files

Here is how to include images (or any other static file like .css, .js, etc.) in your pages.

At the root of your oTree project, there is a _static/ folder. Put a file there, for example puppy.jpg. Then, in your template, you can get the URL to that file with {% static 'puppy.jpg' %}.

To display an image, use the <img> tag, like this:

<img src="{% static 'puppy.jpg' %}"/>

Above we saved our image in _static/puppy.jpg, But actually it’s better to make a subfolder with the name of your app, and save it as _static/your_app_name/puppy.jpg, to keep files organized and prevent name conflicts.

Then your HTML code becomes:

<img src="{% static "your_app_name/puppy.jpg" %}"/>

(If you prefer, you can also put static files inside your app folder, in a subfolder called static/your_app_name.)

If a static file is not updating even after you changed it, this is because your browser cached the file. Do a full page reload (usually Ctrl+F5)

If you have videos or high-resolution images, it’s preferable to store them somewhere online and reference them by URL because the large file size can make uploading your .otreezip file much slower.

Wait pages

Custom wait page template

You can make a custom wait page template. For example, save this to your_app_name/templates/your_app_name/MyWaitPage.html:

{% extends 'otree/WaitPage.html' %}

{% block title %}{{ title_text }}{% endblock %}
{% block content %}
    {{ body_text }}
        My custom content here.
{% endblock %}

Then tell your wait page to use this template:

class MyWaitPage(WaitPage):
    template_name = 'your_app_name/MyWaitPage.html'

Then you can use vars_for_template in the usual way. Actually, the body_text and title_text attributes are just shorthand for setting vars_for_template; the following 2 code snippets are equivalent:

class MyWaitPage(WaitPage):
    body_text = "foo"
class MyWaitPage(WaitPage):

    def vars_for_template(player):
        return dict(body_text="foo")

If you want to apply your custom wait page template globally, save it to _templates/global/WaitPage.html. oTree will then automatically use it everywhere instead of the built-in wait page.


To customize the name “points” to something else like “tokens” or “credits”, set POINTS_CUSTOM_NAME, e.g. POINTS_CUSTOM_NAME = 'tokens'.

You can change the number of decimal places in real world currency amounts with the setting REAL_WORLD_CURRENCY_DECIMAL_PLACES. If the extra decimal places show up but are always 0, then you should reset the database.

Reading CSV or other files

Store yourfile.csv in your app folder. Then put this code anywhere you want to read the file (in a method or in Constants):

import csv
with open('yourapp/yourfile.csv', encoding='utf-8') as file:
    rows = list(csv.DictReader(file))

If it’s not CSV and you just want to read the file contents as a string, this gets simplified to:

with open('yourapp/yourfile.txt', encoding='utf-8') as file:
    txt =