The Private Plugin "Polling" strategy offers a few ways to gather data for your plugins.
Static Endpoints
Provide as many URLs as you'd like, line-separated in the Polling URL box.
Each endpoint can yield a different format (JSON, XML, etc), so long as they all work with the same HTTP Verb, defined separately.
Endpoints will be pinged sequentially, with results going inside index-based JSON nodes like so:
{
"IDX_0": {"data": "stuff here from some-data-source.com" },
"IDX_1": {"data": "stuff here from anothersite.io" },
"IDX_2": {"data": "stuff here from my-server.net" }
}
Dynamic Endpoints
Polling URLs become more powerful by interpolating values into them, for example:
https://twitter.com/api/tweets?access_token={{ api_key }}This api_key value points to a custom form field with "api_key" set as the keyname. Learn how to build form fields here.
In addition to user-provided values, you have access to the entire Liquid templating library. Here's an example that interpolates today's date:
# convert "now" time helper into YYYY-MM-DD
https://reddit.com/api/posts.json?since={{ "now" | date: "%Y-%m-%d" }}
# result
https://reddit.com/api/posts.json?since=2025-10-29
For more examples of advanced Liquid syntax, see here and here. For custom filters (or to propose one for us to build), go here.
Dynamic URLs
Putting together the concepts of multiple URLs and value interpolation, you may also use Liquid to build an arbitrary set of URLs at runtime.
Suppose you want a dashboard of every plugin you've published for other users to install, like this one by Daniel Sitnik:
To achieve this you can define a custom form field, recipe_ids with either the "string" or "multi-string" field type:
Which creates the following user experience:
Next, inject Liquid into your Polling URL markup that iterates those user values:
{% assign ids = recipe_ids | split: "," %}
{% for id in ids %}https://usetrmnl.com/recipes/{{ id }}.json
{% endfor %}
This will generate URLs on the fly, like so:
https://usetrmnl.com/recipes/49610.json
https://usetrmnl.com/recipes/18267.json
https://usetrmnl.com/recipes/11914.json
You can even define URLs without form field inputs, for example:
{% assign recipe_ids = '49610,18267,11914' %}
{% assign ids = recipe_ids | split: "," %}
{% for id in ids %}https://usetrmnl.com/recipes/{{ id }}.json
{% endfor %}
This will yield the same result as above.
Troubleshooting
Testing syntax
Use the "Parse" button below the Polling URL box to test your Liquid markup without waiting for a refresh or clicking Save.
Managing line breaks
On the backend, TRMNL firsts injects your Polling URL content into the Liquid template engine, then* splits the resulting content into separate URLs by detecting line breaks (\r, \n characters).
If your Liquid syntax creates empty line breaks, that's OK, they will be ignored. But if your markup renders like below, it will be considered 1 URL and not behave as you expect:






