How to add dashboard tabs programmatically in Metabase 0.49 – which endpoints to use?

Hi everyone,

I’m running Metabase 0.49 and I’d like to add tabs to a dashboard programmatically instead of creating them manually in the UI.

I’ve reviewed the API endpoints for dashboards, cards, and parameters, but I can’t find clear documentation on:

  • Which API endpoint handles creating and managing dashboard tabs.

  • Whether tabs are created via the /api/dashboard endpoint with a specific payload, or if there’s a separate /api/dashboard-tab (or similar) endpoint.

  • The required JSON structure for creating a tab and assigning cards to it.

I’ve already tried updating the dashboard with the PUT /api/dashboard/:id endpoint (as per the docs) by adding tab-related fields to the payload, but it does not create a new tab

My goal is to automate dashboard creation from a script, including multiple tabs with different cards.

If anyone has examples of API requests for creating tabs in 0.49, that would be a huge help.

Thanks in advance!

Very good question, I have the same need and can’t find any topic related to it, would be interested by the answer

There isn’t a separate API for the dashboard tabs. The tabs are part of the definition of the dashboard.

Look at the API docs on your server:

https:///api/docs

Then look at api/dashboard, passing the id of one of your existing dashboards with tabs.

You’ll see the tab definitions near the end, then each question has a ‘dashboard_tab_id’.

Thanks for your answer.
Yes this I know, I can access the tabs id though this. But what I want is to duplicated a dashboard, creating the exact same number of tabs before attaching duplicated cards to it.

But even with the information on dashboard_tab_id, there is no “post” endpoint that can post a tab based on an ID. Well at least I didn’t find it..

Looking at what the frontend does when it creates a new tab, it calls PUT /api/dashboard/:id and for the new tab uses the magic -2. The response returns the updated dashboard object but the tab will have a new ID filled in.

After some trial and error, I was able to get this working.

I used the PUT /api/dashboard/{id}/cards endpoint with a payload like this:

{
"cards": [
{
"card_id": 16,
"parameter_mappings": [mapping if any],
"size_x": 3,
"size_y": 3,
"row": 0,
"col": 0,
"dashboard_tab_id": 1
},
{
"card_id": 17,
"parameter_mappings": [mapping if any],
"size_x": 3,
"size_y": 3,
"row": 0,
"col": 0,
"dashboard_tab_id": 2
}
],
"tabs": [
{ "id": 1, "name": "MyTab1" },
{ "id": 2, "name": "MyTab2" }
]
}


Using the hint of dwhitemv I could not make this work, I created function looking like this:
`def create_dashboard_tab(mb: Metabase,
dashboard_id: int,
name: str,
description: Union[None, str] = None,
raise_error: bool = True) -> dict:
"""Create a new tab in a dashboard using magic id -2 (Metabase Cloud).

Args:
    mb (Metabase): metabase object
    dashboard_id (int): ID of the dashboard
    name (str): name of the new tab
    description (None|str): description of the tab (optional)
    raise_error (bool): raise if API call fails

Returns:
    dict: Updated dashboard object with the new tab
"""
payload = {"tabs": [{"id": -2, "name": name, "description": description or ""}]}
url = f"/dashboard/{dashboard_id}"

resp = mb.put(url, json=payload)  # retourne juste un bool
if raise_error:
    _raise_resp(resp, request_type="put", url=mb.endpoint + url, params=payload)`

Put it was not duplicating the tabs of my dashboard in a new one, even if tabs were detected.

@abilash , so you did’nt use any put method on tabs, just on cards, and it was creating tabs within a dashboard ? I can’t see how this works if you didn”t created tabs before

Yes, I only used the PUT /api/dashboard/{id}/cards endpoint and it worked for me. Maybe the tabs are just a logical grouping, but with that payload containing only cards, everything works fine on my end. Earlier, I had even tried using the special -2 as the tab ID, but that didn’t help.

1 Like

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