add_custom_data
ChatGPTSave marketing data from a platform DashThis doesn't support natively, so it becomes a real data source on the account. Use when: the user has seen what prepare_custom_data reported AND has confirmed the reading of it — the columns, their formats, how each metric combines — not merely the name. This changes their account. Returns: the source it saved to, how many rows were written, and how many that source now holds. Rules: pass the same 'platform', 'sourceName' and 'table' passed to prepare_custom_data. Calling again with the same source name tops that source up instead of creating a second one — same period and same breakdown replaces, anything new is added. That is what makes a multi-pass import safe: send one date range per call until it is all in, and re-sending a range is never a doubling. Send those calls ONE AT A TIME, waiting for each to come back before the next: saves to one source are applied one after another, so a call still in flight is time the next one spends waiting, and the row counts each reports only line up when they are sequential. Column order doesn't matter. A table carrying a column the source doesn't have adds that column; a table missing one the source has is refused, because it would blank that column on every date it covers — include every existing column, and removing one isn't available here yet. This only ever adds and overwrites, never deletes. Resending a period with the same breakdown corrects its numbers — but nothing here can remove a row that shouldn't be there, so if the user needs rows deleted, say so plainly and point them at DashThis support. If the user asked for this data on a specific dashboard, save it here first — a source has to exist before it can go on one. Then: tell the user what actually changed — this returns rows added and rows overwritten separately, so report those rather than saying 'saved'. It returns the sourceId: to put the source on a dashboard, confirm with the user and pass that id to add_data_source_to_dashboard. That puts the data source there; the widgets are still theirs to build in DashThis.
add_data_source_to_dashboard
ChatGPTPut one data source on one of the account's dashboards, so widgets can be built on it. Use when: the user has just saved data with add_custom_data (when it is listed) and wants it on a dashboard — that call returns the sourceId to pass here — or when search_data_sources found the source they meant. Name the source ONE of three ways, in this order of preference: 'sourceId' when a previous call gave you one; 'connectionId' plus 'providerKey' exactly as search_data_sources returned them; or 'sourceName' as a last resort, which looks only among sources DashThis already holds and refuses rather than guessing between several. Returns: whether it was added, the source's id, and how many plan source slots it used. Rules: one source per call. Confirm with the user first — this changes a dashboard they may be sending to a client. A source already used on another dashboard costs no slot; one used nowhere claims one, and the call is refused rather than taking the account over its plan limit. Adding a source the dashboard already has is harmless. It does not build widgets, and it cannot connect a platform the user hasn't connected in DashThis. Then: say which source landed on which dashboard, and that the widgets are still theirs to add in DashThis.
attach_narrative
ChatGPTPut a narrative saved with write_narrative into one of its dashboard's comment boxes, so the dashboard shows it for that period. This changes a dashboard the user may be sending to a client. Use when: the user wants a saved narrative on the dashboard. Find the box with get_dashboard_metadata: the widgets whose kind is "comment". Returns: the comment box and the date the comment was filed under. Rules: confirm with the user first, and name the box when there are several. When the box already holds a comment for that period the call is refused and hands back that comment: show it to the user, and call again with overwrite only once they agree to replace it. On a periodic dashboard the comment also shows in later periods until one gets its own. On a dashboard whose client picks the dates, the box holds one comment for every period. Then: tell the user which box now shows the narrative, and for which period.
check_dashboard_update
ChatGPTCheck a change update_dashboard would make, without saving anything. Read-only: it takes update_dashboard's arguments and runs every check update_dashboard runs before it saves, and gives the refusal update_dashboard would give. Use when: a change should be known to hold before it is put to the user. Returns: the refusal, or that the change holds, the version it was checked against, and what the user should hear before agreeing: the platforms whose added widgets would show Sample Data, the data sources they would read, size warnings, and widgets that would lose a relative period. Then: fix a refused change and check it again, or call update_dashboard with the same arguments once the user agrees. update_dashboard runs every check again, so a change that held can still be refused when the dashboard, its data sources or the plan's slots changed in between.
connect_integration
ChatGPTGet a link the user opens in their browser to connect one integration to their DashThis account. Use when: the user wants a dashboard on their real numbers and search_data_sources shows no connection to that platform, or a connection needs reconnecting. Returns: the link and the integration's name. Rules: this call connects nothing by itself. The user signs in to DashThis if they aren't already, then to the platform, and DashThis saves the connection on the account they are signed in to. Give the link as is — it is made for this user. Then: once the user says they are done, call search_data_sources with the integration's name to see the new connection and its data sources.
create_custom_dashboard
ChatGPTCreate a DashThis dashboard whose widgets AND layout you specify yourself, rather than letting the AI designer pick them. This adds a dashboard to the user's account. Use when: the user has told you which numbers they want, how the dashboard should read, or asked for something the designer's proposal missed. When they would rather describe their goals and have a dashboard designed for them, use propose_smart_dashboard instead when it is listed. Confirm with the user first: walk them through the sections and widgets you plan, and which platforms will show their own data and which Sample Data, and call this once they agree. This is the step that changes their account. Layout: sections flow top to bottom, each an optional heading over rows of widgets; rows are laid out exactly as you send them — nothing is repacked, resized or restyled. A text format widget carries a block of your own HTML; give sections a heading and an intro text block when the user wants a report that reads like one. Returns: the new dashboard's id and a link to open it, and the widget list — each carrying the metric and dimension ids the server resolved and the grid position it took, so you can check them against what you sent. When any widget cannot be built nothing is created, and the error text names every refused widget, the rule that refused it and why; the whole dashboard is refused, never half of it. Rules: call get_integration_metadata first for every platform you name, and copy its metric and dimension ids verbatim — a widget naming something that does not exist is refused, and inventing an id wastes a call. To filter a widget, read the platform's filter fields first — get_integration_metadata with includeFilters — and author the filter from what it returns. Pass the user's own data sources in 'sources' when they want their real data; each platform without one is built on Sample Data. Google Sheets and Custom Data have no Sample Data and no metrics of their own: they are read from, and built on, the user's own source only. A metric or dimension marked custom in get_integration_metadata belongs to one data source: pass that source to get_integration_metadata to see it, and the same source in 'sources' here, or the widget is refused. A single-figure shape shows one metric; a shape that breaks data down can carry several, so put together the ones the user would read side by side. Pass a theme (themeId or palette) only when the user asked for a particular look. Each successful call creates another dashboard, so never call it again to adjust one already created: change its title, theme or data sources, what a widget shows or where it sits, or add or remove widgets, with update_dashboard when it is listed, and anything else in DashThis. If a call returns no answer or times out, call list_dashboards and look for this title before calling again: the first call may have created it. Then: give the user the link and say which platforms show their real data and which show Sample Data. On a refusal nothing was created: fix what the reasons name and call again with the same 'sources' unless the user changes them — do not drop a widget silently, the user asked for it.
create_dashboard
ChatGPTCreate a real DashThis dashboard from a proposal the user has seen and approved. This adds a dashboard to their account. Use when: the user has reviewed a proposal from propose_custom_dashboard, or from propose_smart_dashboard when it is listed, and wants it built. Confirm with them first — this is the step that changes their account. Returns: the new dashboard's id and a link to open it in DashThis. Rules: pass the generationId of the proposal the user approved. Only that proposal's widgets are created — refine by proposing again rather than describing edits here. Calling again with the same generationId returns the dashboard already created rather than a second copy — and that dashboard keeps its own title, so a title passed on such a call comes back as titleNotApplied unless it is the one the dashboard already has. The theme the proposal shows, if any, is applied with it; this tool takes no theme, so to change it propose again. The data sources named when proposing are linked here; a source new to the account claims a plan source slot, and the call is refused rather than going over the plan limit. Then: give the user the link and say which platforms show their real data and which show Sample Data.
export_dashboard_pdf
ChatGPTTurn a dashboard into a PDF and get a link to it, so the user can hand their client the report itself rather than a login. Use when: the user wants the dashboard as a file — to email a client, attach it to a recap, or keep it with their notes. Returns: a temporary link to the rendered PDF, plus the dashboard's title and the period it covers. The PDF always covers the dashboard's own reporting period — there is no way to export a different window, so if the user wants another period they need to change it in DashThis first. Rules: the link expires after an hour, so give it to the user right away and tell them it is temporary rather than saving it for later. Rendering takes around ten seconds, and this call waits for it. If it comes back still rendering, there is no link yet and nothing reported a failure — say it is taking longer than usual and offer to try again; calling again starts a fresh render. Then: give them the labelled link from the response rather than the bare address, say which dashboard and period it covers, then offer to draft the recap or client email it goes out with.
get_dashboard_data
ChatGPTPull a dashboard's current values so you can help the user make sense of them and communicate them to their client. Use when: the user wants the actual numbers on a dashboard — to summarize performance, spot what moved, or draft an update for a client or stakeholder. Returns: per widget, its title, kind and read status. A data widget carries its metric columns and current-period rows (dimension values + one raw value per metric), plus the matching comparison-period rows when compareTo is set. A widget whose content can't be read here comes back status=unsupported or status=failed with a reason — the dashboard may still display it, so don't report it as empty. A text widget carries the text written on it as content, as HTML — often the user's own commentary about the numbers, with contentPeriodEndDate saying which period it was written for. Values are read over the dashboard's own period unless you ask for another one, and the response says which window answered — name that window whenever you report the numbers. Rules: values are raw as the widget returns them, so compute deltas and format for the reader yourself, and never state a metric or number the widget didn't return. A total is one of those numbers: report the widget's own currentTotals and never work one out from the rows. Then: turn the numbers into the story the user needs — what changed and why it matters to their client — and offer to draft the update in whatever tool they use.
get_dashboard_metadata
ChatGPTRead a dashboard's setup — its sections and widgets, data sources, theme, and reporting-period settings — so you can explain how it's built before working on it further. Use when: the user asks what's on a dashboard, how it's set up, which sources feed it, or wants an overview before pulling its numbers; when they want widgets from it on a new dashboard; or when they want the commentary written in its comment boxes. Returns: the dashboard's info (title, type, culture, reporting period/frequency); its sections of rows of widgets, each with its title, position and size and, when propose_custom_dashboard can rebuild it, its configuration as that tool takes it (platform, metrics, dimension, filters, options, size, and a comment box's text); the data sources connected to it (with their ids, integration and connection status); the integrations used; and the applied theme. Rules: this is the dashboard's setup, not its numbers — it never returns metric values. Use get_dashboard_data for what each widget shows. To put widgets from it on a new dashboard, send their config to propose_custom_dashboard in sections and rows, with each widget's sourceId in sources. A copy keeps each widget's data, shape and size, but not its metric labels, number formats, decimals, up/down colouring, note or own period: say so before the user relies on them. A widget whose config is null cannot be rebuilt that way; configUnavailableReason says why. Then: help the user with what they're actually after — walk them through the setup, explain what a widget covers, or move on to get_dashboard_data for the numbers. Communicating what's there is the default, not flagging what to change. Read-only.
get_integration_metadata
ChatGPTRead what widgets can be built for one integration — the same thing the dashboard proposal tools call a platform: its ready-made presets, and the metrics and dimensions available for composing a widget no preset covers. Use when: you are about to name widgets for a dashboard and need to know what actually exists. Never guess a widget, metric or dimension — names that look plausible on another integration usually do not exist on this one, and a widget naming something that does not exist is refused. Returns: the integration's presets (id, name, shape), its metrics (id, name, group) and its dimensions (id, name). Ids are passed back verbatim; names are for talking to the user. Rules: one integration per call — ask again for each one you need. An integration with many metrics returns the first batch and says how many more matched; pass search to narrow to the ones you want, as many terms at once as you need (["cost", "conversion", "followers"] in one call, not three) — every term is searched, and the batch is shared between them so a broad term cannot crowd out a narrow one, closest matches first. Search also matches a metric's former name, so the vocabulary the user is used to still finds it. Ask for includeDescriptions only when a name alone does not tell you what a metric means — it roughly triples the answer's size. Ask for includeFilters to tell the user what a widget here can be filtered on: it adds the fields, with the operators and values each accepts. Pass sources (found with search_data_sources) to add what the user's own data source defines itself, such as GA4 custom metrics and dimensions or Meta custom conversions, flagged custom, and the filter values only that source has, such as the action types a Meta ad account uses. A custom id is valid only with the source it came from: pass the same sources to propose_custom_dashboard. Without sources the answer is the platform's own vocabulary. Google Sheets and Custom Data have no Sample Data and no metrics of their own: they are read from, and built on, the user's own source only. Then: prefer a preset when one covers the need, and compose from a metric plus an optional dimension only when none does. Read-only — nothing on the account is changed.
list_dashboards
ChatGPTLists the dashboards in the user's account so you can find one or scan across clients. Use when: the user wants an overview of their dashboards, asks "what dashboards do I have", or is about to work on a specific dashboard's report. Returns: a page of dashboards — each with id, title, group, View-mode URL, creator, and creation date (data sources only when includeSources is set) — plus the total count and paging info. No client entity exists — infer client grouping from group and names. Filter server-side to keep results small and targeted: titleContains, integration, hasSourceError. Page with offset/limit. Turn on includeSources only when the user cares about a dashboard's data sources — it makes the response much larger. Then: offer the useful next move in the user's own words — open a dashboard's report, prep a client recap, reconnect a source in error, or share a View URL — one step at a time. Read-only.
prepare_custom_data
ChatGPTCheck how DashThis would interpret marketing data from a platform DashThis doesn't support natively. Use when: the user wants numbers in DashThis from a tool that isn't a native integration, and you can get those numbers — from that platform's own MCP server, a screenshot they paste, or a file they have open. Returns: what each column would become — a date, a metric, or a dimension — with its format and whether it would be summed or averaged, anything DashThis corrected, and anything wrong with the data itself — unreadable dates, repeated rows, blanks, missing days. Rules: pass the whole table as text in 'table' — a markdown table is ideal, and tab-separated or CSV also work. More data than one call carries is normal: a data source is filled over several calls, one date range at a time, and this tool tells you the ranges to send. Bring it in over a few passes rather than telling the user it is too much. For history the user won't report on day by day, monthly totals are far fewer rows and usually what a report wants. The first line must be the column headers. Include exactly one date column and at least one numeric column. Prefer a markdown or tab-separated table over CSV, because amounts like $12,480.00 contain commas. Keep currency symbols on amounts — they are what marks a column as money rather than a plain number. IMPORTANT: this saves nothing on its own. It is the check step. It also reports whether that source already exists and what it holds, so use it before every save, including a top-up. Then: show the user how EVERY column read — its role, its format, and whether it is summed or averaged — and get an explicit yes on that reading, not just on the name. The returned guidance lists the questions to put to them; ask them naming their own columns, because only they know that a column called 'ROI %' is a percentage. If issues comes back with anything marked RowsWouldBeLost, lead with that — part of their table would be discarded — and ask them to fix it and resend. If the source already exists, tell them what it holds so they know this adds to it. If similarlyNamedSources comes back non-empty, ask the user which source they meant before saving anything. Calling again after a correction is free — it saves nothing. Once they have confirmed the reading, call add_custom_data with the same platform, sourceName and table — that is what actually saves it.
provide_feedback
ChatGPTReport back to the DashThis team when these tools can't do what the user needs, or when the user shares something about using them that's worth passing on. Use when: the user wants something no tool here does (creating or editing a dashboard, sending a report, alerts — anything beyond reading); a tool kept failing or was refused; the values you got back clearly weren't what they asked about; getting there took a lot of guessing; or the user tells you something is wrong, missing, confusing, not how they work, or better than they expected. Returns: a reference for the report when it was recorded and none when it wasn't, plus the help center and support ticket links to hand the user. Rules: once per problem, not once per turn. A gap you hit yourself you report on your own; anything the user said is theirs — ask before sending it, and set source to match. Logging a report is not a fix and nobody replies to it; the ticket link is what reaches a person. Then: say it's been logged only when this call hands back a reference, and quote that reference — no reference means no report, whatever you meant to do. Where something couldn't be done, also say plainly what, give them the link that fits, and offer the nearest useful thing you can do instead; where nothing was blocked, none of that applies — the call's own response says which.
search_data_sources
ChatGPTFind the data sources an account can put on a dashboard, across every platform it has connected. Use when: the user wants a source on a dashboard and you have no sourceId for it — search first, then pass what comes back to add_data_source_to_dashboard. Searches two things. Sources DashThis already holds are found straight away, whatever the platform. Sources that exist on the platform but nobody has picked yet are found only once the search names ONE connection — asking every connection would mean calling every platform — so pass 'connection' (or an 'integration' the account has only one connection to) when the first search comes up short. Returns: each source with its connectionId and providerKey, plus a sourceId when it is already set up; and the connections searched, so you can narrow to one. Rules: this creates nothing and changes nothing. If several sources could be meant, put them to the user and let them choose — never guess, because the wrong one puts another client's numbers on a report. Then: name the source, its platform and its connection when you report back — one client often has several accounts on the same platform — and its status when it is in error.
update_custom_data_source
ChatGPTChange an existing custom data source itself — rename it, or stop reporting on one of its columns. Use when: the user wants a column gone from a custom source, or the source renamed. Not for changing the numbers — resend the corrected table with add_custom_data. Returns: what was removed or renamed, and the columns the source still has. Rules: confirm with the user first — a widget built on a removed column stops showing anything. Removing a column keeps its stored values, so sending that column again brings it back with its history intact. A column that breaks the data down (a dimension) can't be removed, and neither can the date column. Then: say what changed and warn them about any widget built on a removed column.
update_dashboard
ChatGPTChange an existing dashboard's title, theme or data sources, change, move or remove its widgets, or add widgets. This changes the user's dashboard. Use when: the user wants a dashboard renamed, given another look, or switched from Sample Data, or from one data source, to another source on the same platform; or wants a widget to show other metrics, another breakdown or other filters, to carry another title, note or display options, to take another shape or size, or to report on a period of its own, such as the last 30 days, instead of the dashboard's; or wants widgets or sections moved or removed; or wants widgets added to a dashboard that exists, new ones or copies of widgets on another dashboard. Confirm with the user first: say what will change — the new title, the theme, for each source which widgets will switch and that filter values and goals on them carry over unchecked, for each widget what it will show or where it will go, each widget to remove by name, and the widgets to add with the data each will read — and call this once they agree. Removing is permanent: DashThis has no undo, so never remove a widget the user has not named or agreed to. Rules: read the dashboard with get_dashboard_metadata first and pass its version as expectedVersion. When the dashboard changed since, the call is refused with DashboardChanged: read it again and check the change with the user before calling again. Only periodic dashboards can be changed here. Every field reads one way: left out or empty keeps its value, sent replaces it whole, and named in a widget entry's clear list is emptied. In replaceSources, each entry names a source on the dashboard and its replacement, found with search_data_sources, on the same platform; leave the sourceId empty to replace that platform's Sample Data. Filter values and goals carried over from the replaced source (a campaign or page, for instance) are not checked, and widgets DashThis cannot rebuild from their settings, such as formulas or older widgets, switch with no check: when the user's widgets filter on source-specific values or goals, say so and ask them to review those. A replacement not yet used on one of the user's dashboards takes one of the plan's source slots. In editWidgets, each entry names a widget by the id get_dashboard_metadata returns and sends the config fields to change, named as its config names them; the widget keeps its id and its data source. A new format keeps the size, dimension and options the entry leaves out, and is refused when they do not fit it: then send a size, or clear dimensionId or options. positionX and positionY move a widget's top-left corner on the 8-column grid; a new size keeps the corner unless the entry moves it. The layout is judged once every entry applies, so widgets can trade places in one call, and it is refused when a widget would pass the right edge or cover another; nothing is pushed aside. To move a section, move its heading and each of its widgets. A comment box takes only a new size or position; its text is written with write_narrative. period gives a widget a period of its own, a preset or custom dates, only on a dashboard with Flexible Period on (get_dashboard_metadata's datePickerEnabled); clear period to have it follow the dashboard again. Section headings, comment boxes, tables typed into DashThis and editable numbers take no period. A period touches at most 60 months, and a chart shown by day or week draws at most 60 points: a longer one is refused, naming the granularity that fits. removeWidgets removes widgets by id, section headings included; removing a heading leaves its widgets in the section above. Removing a widget frees no data source and no plan slot. In addSections, sections are laid out as create_custom_dashboard lays them out and go below the dashboard's last row, or, with addBefore, at the row of that widget, where the widgets from that row down make room. Then the grid settles as DashThis shows it, so a widget can end up beside a narrower added section, and an added widget beside a shorter one above it. A first section with…
whoami
ChatGPTConfirms which DashThis account this session is acting on. Returns the account resolved from the access token, its company name, status, and dashboard count, and, when a DashThis staff member is using the connection on a customer's behalf, both of them.
write_narrative
ChatGPTSave written analysis of one of a dashboard's periods: the commentary a marketer puts in front of their client. This saves it in DashThis; it does not show it on the dashboard yet, which is what attach_narrative does. Use when: the user has agreed on commentary for a dashboard period and wants it kept or put on the dashboard. Name the period the way get_dashboard_data does ("2026-08", "2026-Q3", or its exact dates "2026-08-01..2026-08-31"). It must be one of the dashboard's own periods, whole. Leave it empty for the dashboard's last completed period. Returns: the narrative's id and the period it is about. Rules: one narrative per dashboard period. When one already exists the call is refused and hands back its id: attach that one, or call again with overwrite only once the user has agreed to replace it. Send the same words twice: text as plain text, html as the formatted version the comment box shows. It keeps what a comment box does: headings, paragraphs, bold, italics, lists, http and https links, tables, colours and inline styles. Style with inline styles, not CSS classes. Don't send scripts, <style> blocks or forms: DashThis removes those tags but keeps the text inside them, which then shows in the box. Then: offer to put it in one of the dashboard's comment boxes with attach_narrative.
add_custom_data
Claudeadd_data_source_to_dashboard
Claudeattach_narrative
Claudecheck_dashboard_update
Claudeconnect_integration
Claudecreate_custom_dashboard
Claudeexport_dashboard_pdf
Claudeget_dashboard_data
Claudeget_dashboard_metadata
Claudeget_integration_metadata
Claudelist_dashboards
Claudeprepare_custom_data
Claudeprovide_feedback
Claudesearch_data_sources
Claudeupdate_custom_data_source
Claudeupdate_dashboard
Claudewhoami
Claudewrite_narrative
Claude