Windsurf Analytics API (SaaS)
Overview
Windsurf supports an API for custom analytics. It allows querying for data from autocomplete, chat, and command, and a variety of filters, groupings, and aggregations.
We provide all examples in curl; it can then be translated into HTTP requests in other languages.
User Data Analytics API specification
Data from the Users table on the teams page can be obtained with the following command:
SERVICE_KEY: The service key - an admin user can create one from the service key section of the settings page. The role of the service key must have “Teams Read-only” permissions.
GROUP_NAME: The name of a group to filter on. This field is optional.
START_TIMESTAMP/END_TIMESTAMP: Timestamps in RFC 3339 format, so e.g. 2023-01-01T00:00:00Z
Example output
Cascade Analytics API Specification
The Cascade specific data seen on the analytics page can be queried via API.
SERVICE_KEY: The service key - an admin user can create a new one from https://windsurf.com/team/team_settings
GROUP_NAME: The name of a group to filter on. This field is optional. Can not be set if emails is set.
START_TIMESTAMP/END_TIMESTAMP: Timestamps in RFC 3339 format, so e.g. 2023-01-01T00:00:00Z
EMAILS: A list of emails to filter on. This field is optional. Can not be set if group_name is set.
IDE_TYPES: A list of IDE types to filter on. This field is optional. The possible values are described below.
QUERY_REQUESTS: A list of query requests to make. This field is required. The possible values of CASCADE_DATA_SOURCE are described below.
Example Query
IDE Types
We split cascade data in to two categories, the Editor and the JetBrains Plugin. Excluding the ide_types field in the query returns data for both. If you would like to query data for only one of the IDEs, you can use either of the two options:
- “editor” for the Windsurf Editor
- “jetbrains” for the JetBrains Plugin
Cascade Data Sources
There are three possible values for CASCADE_DATA_SOURCE
Source: cascade_lines
Use cascade_lines to query for data on cascade lines suggested and accepted per day.
Example output:
linesSuggested: The number of lines suggested on the given day. linesAccepted: The number of lines accepted on the given day.
Source: cascade_runs
Use cascade_runs to query for data on model usage, credit consumption, and mode.
Example output:
day: The date of the run.
model: The model used for the message.
mode: The mode of the run. One of CONVERSATIONAL_PLANNER_MODE_DEFAULT (for write mode), CONVERSATIONAL_PLANNER_MODE_READ_ONLY (for read mode), CONVERSATIONAL_PLANNER_MODE_NO_TOOL (for legacy mode), or UNKNOWN.
messagesSent: The number of messages sent.
cascadeId: The ID of the run. This id can be used to understand how many distinct converstations have been started (as opposed to how many times the user sends a message).
promptsUsed: The number of credits used.
The data returned by the api is in a raw format, which may explain any “UNKNOWN” values. If using this data source for your own metrics, it is recommended to aggregate by the specific metrics you are interested in (eg, count up the promptsUsed field to understand user usage patterns, messagesSent to understand user engagement, etc), as it is possible for mode and prompt data to be split across entries.
Source: cascade_tool_usage
Use cascade_tool_usage to query for data on tool usage. Note that this returns an aggregate count of tool in the provided period.
Example output:
tool: The tool used for the message.
count: The number of times the tool was used.
Here is a map of the returned enums and the human readable name, as it is displayed in the UI:
- CODE_ACTION: ‘Code Edit’
- VIEW_FILE: ‘View File’
- RUN_COMMAND: ‘Run Command’
- FIND: ‘Find tool’
- GREP_SEARCH: ‘Grep Search’
- VIEW_FILE_OUTLINE: ‘View File Outline’
- MQUERY: ‘Riptide’
- LIST_DIRECTORY: ‘List Directory’
- MCP_TOOL: ‘MCP Tool’
- PROPOSE_CODE: ‘Propose Code’
- SEARCH_WEB: ‘Search Web’
- MEMORY: ‘Memory’
- PROXY_WEB_SERVER: ‘Browser Preview’
- DEPLOY_WEB_APP: ‘Deploy Web App’
Custom Analytics API specification
Certain data sources allow for customizable queries via the Custom Analytics API.
Full schemas for selections, filters, aggregations, and orderings are in the following section, in JSON format. Example queries and for each of the three data sources, as well as query debugging tips, will be at the end of the document.
DATA_SOURCE: select either USER_DATA, CHAT_DATA, or COMMAND_DATA depending on whether you are looking for autocomplete, chat, or command data.
SERVICE_KEY: The service key - an admin user can create a new one from https://windsurf.com/team/team_settings
GROUP_NAME: The name of a group to filter on. This field is optional.
Schemas
Selections
Selections are required. Each selection corresponds to a value to be queried.
FIELD_NAME: The field you wish to query. See the Available Fields section below.
NAME: An alias for the field. If not specified, will be the lowercase version of <AGGREGATION_FUNCTION>_<FIELD_NAME>, e.g. sum_num_acceptances. Must be distinct from all other field and aggregation names.
AGGREGATION_FUNCTION: should be one of UNSPECIFIED, COUNT, SUM, AVG, MAX, MIN. If “aggregation_function” is not provided, defaults to UNSPECIFIED.
Filters
Filters are used to narrow down the data to only contain elements that meet certain criteria. They are optional.
NAME: The name of the field you wish to filter. If the filtered item is the same as a Selection/Aggregation, this must be equal to the name of the field/aggregation.
VALUE: the value being compared.
FILTER: One of EQUAL, NOT_EQUAL, GREATER_THAN, LESS_THAN, GE (greater than or equal), LE (less than or equal).
Aggregations
Aggregations are used to split the data into groups based off a specified criteria. They are optional.
FIELD_NAME: The field you wish to query. See the Available Fields section.
NAME: An alias for the field. Must be distinct from all other field and aggregation names.
Available Fields
User Data
All data from the USER_DATA source is aggregated per user, per hour.
Note: PCW (percent code written) now has its own table, and does not rely on the user_data table.
Field Name | Description | Valid Aggregations |
---|---|---|
api_key | A hash of the user API key. | UNSPECIFIED, COUNT |
date | The UTC date of the autocompletion(s). | UNSPECIFIED, COUNT |
date UTC-x | The date of the autocompletion, with a time zone offset. For example, PST would be “date UTC-8”. | UNSPECIFIED, COUNT |
hour | The UTC hour of the autocompletions(s). | UNSPECIFIED, COUNT |
language | The programming language being used. | UNSPECIFIED, COUNT |
ide | The IDE that was being used. | UNSPECIFIED, COUNT |
version | The Windsurf version used | UNSPECIFIED, COUNT |
num_acceptances | The number of times the user accepted an autocomplete. This occurs when the user writes some code, sees grey text, and presses tab. | SUM, MAX, MIN, AVG |
num_lines_accepted | Lines of code accepted from autocomplete. | SUM, MAX, MIN, AVG |
num_bytes_accepted | Bytes accepted from autocomplete. | SUM, MAX, MIN, AVG |
distinct_users | Distinct users. | UNSPECIFIED, COUNT |
distinct_developer_days | Distinct (users, day) tuples. | UNSPECIFIED, COUNT |
distinct_developer_hours | Distinct (users, hour of day) tuples. | UNSPECIFIED, COUNT |
Chat Data
Note that all data provided in the chat data API are for the chat model responses, not the user questions.
Field Name | Description | Valid Aggregations |
---|---|---|
api_key | A hash of the user API key | UNSPECIFIED, COUNT |
model_id | The chat model’s ID, set during deployment time. | UNSPECIFIED, COUNT |
date | The UTC date of the chat response. | UNSPECIFIED, COUNT |
date UTC-x | The date of the chat response, with a time zone offset. For example, PST would be “date UTC-8”. | UNSPECIFIED, COUNT |
ide | The IDE that was being used | UNSPECIFIED, COUNT |
version | The Windsurf version used | UNSPECIFIED, COUNT |
latest_intent_type | Whether the model response is generated from a code lens or a regular chat. Regular chats will correspond to: CHAT_INTENT_GENERIC while code lenses will correspond to one of: CHAT_INTENT_FUNCTION_EXPLAIN CHAT_INTENT_FUNCTION_DOCSTRING CHAT_INTENT_FUNCTION_REFACTOR CHAT_INTENT_CODE_BLOCK_EXPLAIN CHAT_INTENT_CODE_BLOCK_REFACTOR CHAT_INTENT_PROBLEM_EXPLAIN CHAT_INTENT_FUNCTION_UNIT_TESTS | UNSPECIFIED, COUNT |
num_chats_received | Number of chats messages sent from Windsurf to the user. | SUM, MAX, MIN, AVG |
chat_accepted | True if a code block was sent in Windsurf’s chat response, and the Thumbs up button is clicked. | SUM, COUNT |
chat_inserted_at_cursor | True if a code block was sent in Windsurf’s chat response, and the “Insert” button is clicked. | SUM, COUNT |
chat_applied | True if a code block was sent in Windsurf’s chat response, and the “Apply Diff” button is clicked. | SUM, COUNT |
chat_loc_used | Lines of code used, if a code block was sent in Windsurf’s chat, and any of the “Insert”, “Copy”, or “Apply Diff” buttons are pressed. | SUM, MAX, MIN, AVG |
Command Data
Note that the Command Data source contains all commands, including those which were declined. The “accepted” field can be used to filter for only accepted commands.
Field Name | Description | Valid Aggregations |
---|---|---|
api_key | A hash of the user API key. | UNSPECIFIED, COUNT |
date | The UTC date of the command. | UNSPECIFIED, COUNT |
timestamp | The UTC timestamp of the command. | UNSPECIFIED, COUNT |
language | The programming language being used. | UNSPECIFIED, COUNT |
ide | The IDE that was being used. | UNSPECIFIED, COUNT |
version | The Windsurf version used | UNSPECIFIED, COUNT |
command_source | The reason that the command was triggered. Valid values are, COMMAND_REQUEST_SOURCE_LINE_HINT_CODE_LENS COMMAND_REQUEST_SOURCE_DEFAULT COMMAND_REQUEST_SOURCE_RIGHT_CLICK_REFACTOR COMMAND_REQUEST_SOURCE_FUNCTION_CODE_LENS COMMAND_REQUEST_SOURCE_FOLLOWUP COMMAND_REQUEST_SOURCE_CLASS_CODE_LENS COMMAND_REQUEST_SOURCE_PLAN COMMAND_REQUEST_SOURCE_SELECTION_HINT_CODE_LENS COMMAND_REQUEST_SOURCE_DEFAULT corresponds to the typical command usage. | UNSPECIFIED, COUNT |
provider_source | Determines whether command was triggered in generation or edit mode. Valid values are,PROVIDER_SOURCE_COMMAND_GENERATE PROVIDER_SOURCE_COMMAND_EDIT | UNSPECIFIED, COUNT |
lines_added | Number of lines of code added by the command. | SUM, MAX, MIN, AVG |
lines_removed | Number of lines of code removed by the command. | SUM, MAX, MIN, AVG |
bytes_added | Number of bytes added by the command. | SUM, MAX, MIN, AVG |
bytes_removed | Number of bytes removed by the command. | SUM, MAX, MIN, AVG |
selection_lines | Number of lines of code selected by the command. Should always be zero for generations. | SUM, MAX, MIN, AVG |
selection_bytes | Number of bytes selected by the command. Should always be zero for generations. | SUM, MAX, MIN, AVG |
accepted | Whether the command was accepted. | SUM, COUNT |
PCW Data
Valid Selections
Field Name | Description | Valid Aggregations |
---|---|---|
percent_code_written | Percent code written. Calculated as (number of windsurf bytes generated) / (number of windsurf bytes generated + number of user bytes generated). This metric can have high variance within single days or users, so we recommend aggregating over weeks for this. | UNSPECIFIED |
windsurf_bytes | total number of windsurf bytes, which is equal to windsurf_bytes_by_autocomplete + windsurf_bytes_by_command | UNSPECIFIED |
user_bytes | total number of user bytes | UNSPECIFIED |
total_bytes | windsurf_bytes + user_bytes | UNSPECIFIED |
windsurf_bytes_by_autocomplete | total number of windsurf bytes generated from autocomplete | UNSPECIFIED |
windsurf_bytes_by_command | total number of windsurf bytes generated from command | UNSPECIFIED |
Valid Filters
Field Name | Description | Some Examples |
api_key | A hash of the user API key. | |
language | The programming language being used. | KOTLIN, GO, JAVA |
ide | The IDE that was being used. | jetbrains, vscode |
version | The Windsurf version used | 1.28.0, 130.0 |
To filter by date, use start_timestamp and end_timestamp, which should be in RFC 3339 format (e.g. 2023-01-01T00:00:00Z, see in the example below).
Examples
User Data
This query calculates the overall Percent Code Written over the month of January 2024. Example response (JSON formatted for readability):
Chat Data
This query shows the number of lines of code accepted from the “Generate Docstring” code lens, for all time, grouped by IDE.
Example response:
Command Data
This query gets the number of lines added and removed from “edit” commands, grouped by programming language.
Example response:
PCW Data
This query gets the PCW (Percent Code Written) data, along with bytes filtered by language go.
Example response:
Query debugging
From 1.10.0 and on, invalid queries will return an error message. This section has some common error messages, what they mean, and how to debug the corresponding queries.
Error Message | Explanation |
---|---|
at least one field or aggregation is required | Did not detect any selections or aggregations - make sure the query request contains at least one. |
invalid aggregation function for string type field ide: QUERY_AGGREGATION_SUM | One of the selections used an invalid aggregation function. In this case we tried to use SUM on the “ide” field, but it only supports COUNT and UNSPECIFIED |
invalid query table: QUERY_DATA_SOURCE_UNSPECIFIED | There is likely a typo in the data_source field, double check the spelling. |
all selection fields should have an aggregation function, or none of them should | If there are multiple selection fields, either all should contain an aggregation_function, or none of them should. For example, this selection is invalid because num_acceptances is summed, but num_lines_accepted is not: Note: PCW is always considered aggregated. If no aggregation_function is explicitly chosen, it is considered unspecified. If you would like information about both of these fields, use two seperate queries. |
invalid aggregation function for string type field ide: QUERY_AGGREGATION_SUM | Not every field supports every aggregation function; see the available fields section for the matches. In this case, the query used a QUERY_AGGREGATION_SUM aggregation function with the “ide” field, which is invalid. |
tried to aggregate on a distinct field: distinct_developer_days. Consider aggregating on the non-distinct fields instead: [api_key date] | Fields with the pattern “distinct_*” can not be in the aggregations section; the error suggests an alternative field(s) to aggregate on instead. So instead of: Try: |
duplicate field alias for selection/aggregation: num_acceptances | All selections and aggregations must have a different name. Keep in mind that if the name is not specified, by default it is set to <AGGREGATION_FUNCTION>_<FIELD_NAME>. |
invalid group name: GroupName | The group with the specified name was not found, double check the spelling. |