Todoist Integration

It would be great to be able to choose one of my custom Filters (not just Inbox or Today) in my todist account and have it display the items I need to work on.


This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

I would love to see my Today tasks, it that possible?

This thing is so cool!

1 Like

So a friend and I have worked out most of a simple Todoist Integration.

Below is what we have come up with. It finds the most overdue task and adds the date in red (to match the Todoist colouring). Once, you no longer have any overdue tasks, it just shows the task.

If you want to try it out, grab your API Token from the integrations panel of Todoist on a browser:

Copy this code as a text file, save with a .star extension.

Replace the place holder text with you API Token and run it per the instructions on the Pixlet Github docs:

Hopefully, we can work together to make it reliable, add features like respecting priority flags and even add it as a community app.

1 Like
load("", "render")
load("", "http")
load("encoding/", "base64")
load("", "cache")
load("encoding/", "json")
load("", "time")


TODOIST_API_TASKS_URL = TODOIST_API_BASE_URL + "/tasks?filter=(overdue|today)"



CACHE_KEY_MODEL = "todoist_model"

def dateStringToTime(dateString):
    return time.parse_time(dateString, "2006-01-02")

def renderDate(dateString):
    return dateStringToTime(dateString).format("02-Jan")

def isOverdue(date):
    current =
    currentDay = time.time(year = current.year, month = current.month, day =
    return date < currentDay

def main():
    # Download tasks
    resp = http.get(TODOIST_API_TASKS_URL, headers={"Authorization": "Bearer " + TODOIST_API_TOKEN})
    if resp.status_code != 200:
        fail("Get tasks failed with status %d", resp.status_code)
    parsed = resp.json()

    # Compute model to display
    model = None
    for task in parsed:
        due = dateStringToTime(task["due"]["date"])
        thisModel = { MODEL_KEY_TEXT: task["content"] }
        if isOverdue(due):
            thisModel.update([(MODEL_KEY_DUE, task["due"]["date"])])
        if model == None:
            model = thisModel
        if model.get(MODEL_KEY_DUE) == None:
            if thisModel.get(MODEL_KEY_DUE) != None:
                model = thisModel
            if due < dateStringToTime(model[MODEL_KEY_DUE]):
                model = thisModel
    if model == None:
        model = { MODEL_KEY_TEXT: "No more tasks!" }

    # Render model
    children = [
            content = model[MODEL_KEY_TEXT]
    if model.get(MODEL_KEY_DUE) != None:
            children = [
                    content = renderDate(model.get(MODEL_KEY_DUE)),
                    color = "#f00",
                    font = "CG-pixel-4x5-mono"
            expanded = True,
            main_align = "end",
    return render.Root(
        child = render.Column(
            children = children,
            expanded = True,
            main_align = "space_between",
            cross_align = "center"
1 Like

great stuff! works well

Hey @alisdair! Took your code, added an image and some slight tweaks. Put it into the format for a community app and submitted a PR. Included your name as author and a link back here, I hope you don’t mind.

We can use this now to add enhancements.

Pull Request for Community App:
Forked Repo:

1 Like

Hey @alisdair, please check this out if you see this post - we need your permission to merge to app store.


This looks fantastic! Please go ahead with the merge.

1 Like