Skip to content

Excel Add-in

The Excel add-in APIs integrate Datatailr workflows with spreadsheet-based workflows.

Related API pages

Quick start: deploy your first Excel add-in

Step 1: write your Excel add-in

In this example, we will create a simple Excel Add-in that implements some basic functionality.

# my_addin.py

import datatailr.excel

addin = datatailr.excel.Addin(
    "MyAddin",
    "This is a very cool simple Excel addin!",
)

@addin.expose(description="Adds 2 numbers", help="To add 2 numbers give them to the function")
def add(a: int, b: int) -> float:
    return a + b

@addin.expose(description="Subtracts 2 numbers", help="To subtract 2 numbers give them to the function")
def sub(a: int, b: int) -> float:
    return a - b

def __excel_main__(port, debug=False):
    addin.run(port=port)

Step 2: deploy the Excel add-in

Your Excel Add-in deployment can be defined as a datatailr.scheduler.Job object:

# my_addin_deployment.py

from datatailr import ExcelAddin
from my_addin import __excel_main__

addin = ExcelAddin(
    name="my_addin",
    entrypoint=__excel_main__,
)
addin.save()
addin.start()

Running the code above will deploy your Excel Add-in.

Developing and deploying Excel add-ins

Excel add-ins on Datatailr are created automatically from Python modules. Any fully type-annotated functions you expose will be callable from Excel once the add-in is sideloaded.

Develop an Excel add-in

from datatailr.excel import Addin, Queue

Create the add-in

my_addin = Addin("MyAddin", "This is a very cool simple Excel addin!")
Addin(...) parameters
  • name: str - Display name in Excel.
  • description: str - Shown in the taskpane.
  • version: str (optional), default value "1.0.0" - Semantic version.
  • min_update_interval: float (optional), default value 0.5 - exists for compatibility with addins defined for v1. Doesn't do anything.

Expose functions

Decorate fully annotated functions with addin.expose(...).

import time
from datatailr.excel import Queue

@addin.expose(description="Add two numbers", help="Returns a + b")
def add(a: float, b: float) -> float:
    return a + b
addin.expose(...) parameters
  • description: str - Shown in the taskpane next to the function name.
  • help: str - Tooltip shown in the formula bar.
  • volatile: bool = False - Mark as volatile (Excel may recalc more often).
  • streaming: bool = False - If True, the function's first argument must be queue: datatailr.excel.Queue. The return value is ignored; values are sent via queue.push(...).
  • progressbar: bool = False - When True, the function becomes a streaming function that auto-streams a progress bar until the final result is ready.

Streaming functions

import time
from datatailr.excel import Queue

@addin.expose(
    description="Simple numeric ticker",
    help="Streams an increasing number",
    streaming=True,
)
def int_ticker_N(queue: Queue, start: int, N: int) -> int:
    value = start
    for _ in range(N):
        queue.push(value)   # streamed to Excel immediately
        value += 1
        time.sleep(1)
    # return value is ignored for streaming functions

Queue API

  • Queue.push(value: Any) -> None - Streams a value to Excel. Type should match the function's annotated return type.
  • Queue.error(message: str) -> None - Sends an error for the current invocation.

Working with matrices

Excel custom functions may accept and return 2-D lists ("matrices"). Elements may be mixed-type (strings, numbers, etc). Even 1-D vectors must still be represented as a 2-D nested list.

def print_row() -> list:
    return [[1, 2, 3]]

def print_column() -> list:
    return [[1], [2], [3]]

def print_matrix() -> list:
    return [[1, 2], [3, 4]]

Optional parameters

If you define a default for a parameter, Excel treats it as optional. For list-like parameters, follow standard Python practice (avoid mutable defaults):

def foo(x: list | None = None) -> ...:
    if x is None:
        ...

Deploy an Excel add-in

Assume the add-in lives in my_module/my_addin.py:

import datatailr.excel

addin = datatailr.excel.Addin(
    "MyAddin",
    "This is a very cool simple Excel addin as always!",
    version="1.0.0",
)

@addin.expose(description="Adds 2 numbers", help="Provide two numbers")
def add(a: int, b: int) -> int:
    return a + b

Deploying in the IDE (for development)

Run via the IDE proxy for quick testing:

if __name__ == "__main__":
    addin.run(12345, 12346, ide=True)
Addin.run(...) parameters
  • port: int - HTTP port for the download page and non-streaming calls.
  • ws_port: int - WebSocket port for streaming functions.
  • ide: bool = True - Must be True when running inside the IDE. Using False here in the IDE will produce a broken add-in.

Deploying to Datatailr

Create a Job with JobType.EXCEL:

from my_module.my_addin import __excel_main__

from datatailr.scheduler import Job, JobType, EntryPoint, Resources

job = Job(
    "my_addin",
    python_version="3.10",
    resources=Resources(memory="512m", cpu=1.0),
    entrypoint=EntryPoint(type=JobType.EXCEL, func=__excel_main__),
    python_requirements="numpy",
)
job.save()

This will deploy the add-in and make it available with the rest of the deployed applications and add-ins in the dev apps section.

Note: In EntryPoint, you pass a function name (e.g., __excel_main__) to carry the module reference; the function itself is not executed for Excel jobs.