This guide will help you create a new WakaTime plugin for your text editor/IDE.
Let us know if you're building a WakaTime plugin! We can help you via email!
We can also evangelize and help promote your new plugin to all WakaTime users.
A WakaTime plugin is simple… just run the wakatime-cli command and pass it the current file as an argument.
$ wakatime-cli --entity myfile.txt
The code above sends a heartbeat to the WakaTime API and starts logging time.
--key XXXX
.
WakaTime plugins have two parts:
Source code for existing WakaTime plugins can be viewed on GitHub.
This is a high-level overview of a WakaTime plugin from the time it's loaded, until the editor is exited.
~/.wakatime/
if missing or needs an update~/.wakatime.cfg
, prompt user to enter if does not existSend heartbeat
function with isWrite falseSend heartbeat
function with isWrite falseSend heartbeat
function with isWrite trueSend heartbeat
function
lastHeartbeat
variable. if isWrite is false, and file has not changed since last heartbeat, and less than 2 minutes since last heartbeat, then return and do nothinglastHeartbeat
variable with current file and current timeThis happens every time your plugin is loaded, for example when the user opens their text editor/IDE or when the user first installs the plugin.
Examples of init code can be viewed here:
wakatime-cli is a Go command line tool containing common code that every plugin uses. It does things like detect the current project, branch, syntax language, and send heartbeats to the WakaTime api. To send a heartbeat, your plugin should run wakatime-cli in a background process and pass it the absolute path of the current file.
The wakatime-cli binary is downloaded from GitHub releases. We also use the GitHub API to check the latest release version, and update wakatime-cli to the latest release if needed.
In your plugin’s init function, check if ~/.wakatime/wakatime-cli-
exists and that it’s version matches the latest GitHub release.
If wakatime-cli
needs updating or doesn’t exist, download the wakatime-cli zip file for the current OS and architecture from the latest release then unzip it into ~/.wakatime/
.
Examples of downloading and unzipping wakatime-cli can be found here:
The last step when initializing your plugin is setting up event listeners. Most editors support some version of these events:
These three events are the only ones we care about. When one of these three events are detected, your plugin should send the file to wakatime-cli
.
Some examples of listening for these events:
Every event handler should call the same function, sometimes passing the currently focused file as a parameter if needed. The only catch is the File Save
event needs to pass a boolean to indicate this heartbeat was triggered from saving to a file.
The file changed event detects when the editor focus has changed to a new file. For example, when the user switches to a new tab in their editor.
The file modified event should be triggered every time the currently focused file is changed. If your editor only supports detecting the first time a file is modified, you should detect when a user presses a key instead.
The file saved event detects when a file's modified contents are written to disk.
Every event handler should call the same function. This common function should accept one argument, the boolean indicating whether this event was triggered from saving to a file(true
) or not(false
).
The first thing this function should do is detect the currently focused file. If there is no way to detect the currently focused file, the event handlers can pass the current file as an argument.
This function should decide whether to send the file to wakatime-cli
or not, depending on how long it has been since it last sent the same file to wakatime-cli
. Here's some example Python showing this decision:
if enoughTimeHasPassed(lastSentTime) or currentlyFocusedFileHasChanged(lastSentFile) or isFileSavedEvent():
sendFileToWakatimeCLI()
else:
# do nothing
pass
The enoughTimeHasPassed
function checks if more than 2 minutes have passed since this function has executed last, to prevent sending the currently focused file to wakatime-cli
too frequently. In this case, it would check if lastSentTime
times 120
seconds is greater than the current time.
The currentlyFocusedFileHasChanged
function checks if the absolute path to the currently focused file equals lastSentFile
and returns True
if it does not equal and False
if it is equal.
The isFileSavedEvent
function checks the boolean passed from the event handlers, and returns it as-is.
Now that we have decided to send the file to wakatime-cli
, we need to execute it as a background process and pass the current file as a command line argument. For reference, here is the wakatime-cli
help:
$ wakatime-cli [flags]
Flags:
--alternate-language string Optional alternate language name. Auto-detected language takes priority.
--alternate-project string Optional alternate project name. Auto-detected project takes priority.
--api-url string API base url used when sending heartbeats and fetching code stats. Defaults to https://api.wakatime.com/api/v1/.
--category string Category of this heartbeat activity. Can be "coding", "building", "indexing", "debugging", "communicating", "supporting", "advising", "running tests", "writing tests", "manual testing", "code reviewing", "browsing", or "designing". Defaults to "coding".
--config string Optional config file. Defaults to '~/.wakatime.cfg'.
--config-read string Prints value for the given config key, then exits.
--config-section string Optional config section when reading or writing a config key. Defaults to [settings]. (default "settings")
--config-write stringToString Writes value to a config key, then exits. Expects two arguments, key and value. (default [])
--cursorpos int Optional cursor position in the current file.
--disable-offline Disables offline time logging instead of queuing logged time.
--entity string Absolute path to file for the heartbeat. Can also be a url, domain or app when --entity-type is not file.
--entity-type string Entity type for this heartbeat. Can be "file", "domain" or "app". Defaults to "file".
--exclude strings Filename patterns to exclude from logging. POSIX regex syntax. Can be used more than once.
--exclude-unknown-project When set, any activity where the project cannot be detected will be ignored.
--extra-heartbeats Reads extra heartbeats from STDIN as a JSON array until EOF.
--help help for wakatime-cli
--hide-branch-names string Obfuscate branch names. Will not send revision control branch names to api.
--hide-file-names string Obfuscate filenames. Will not send file names to api.
--hide-project-names string Obfuscate project names. When a project folder is detected instead of using the folder name as the project, a .wakatime-project file is created with a random project name.
--hostname string Optional name of local machine. Defaults to local machine name read from system.
--include strings Filename patterns to log. When used in combination with --exclude, files matching include will still be logged. POSIX regex syntax. Can be used more than once.
--include-only-with-project-file Disables tracking folders unless they contain a .wakatime-project file. Defaults to false.
--internal-config string Optional internal config file. Defaults to '~/.wakatime-internal.cfg'.
--key string Your wakatime api key; uses api_key from ~/.wakatime.cfg by default.
--language string Optional language name. If valid, takes priority over auto-detected language.
--lineno int Optional line number. This is the current line being edited.
--lines-in-file int Optional lines in the file. Normally, this is detected automatically but can be provided manually for performance, accuracy, or when using --local-file.
--local-file string Absolute path to local file for the heartbeat. When --entity is a remote file, this local file will be used for stats and just the value of --entity is sent with the heartbeat.
--log-file string Optional log file. Defaults to '~/.wakatime/wakatime.log'.
--log-to-stdout If enabled, logs will go to stdout. Will overwrite logfile configs.
--no-ssl-verify Disables SSL certificate verification for HTTPS requests. By default, SSL certificates are verified.
--offline-count Prints the number of heartbeats in the offline db, then exits.
--plugin string Optional text editor plugin name and version for User-Agent header.
--project string Override auto-detected project. Use --alternate-project to supply a fallback project if one can't be auto-detected.
--proxy string Optional proxy configuration. Supports HTTPS SOCKS and NTLM proxies. For example: 'https://user:pass@host:port' or 'socks5://user:pass@host:port' or 'domain\user:pass'
--ssl-certs-file string Override the bundled CA certs file. By default, uses system ca certs.
--sync-offline-activity string Amount of offline activity to sync from your local ~/.wakatime/offline_heartbeats.bdb bolt file to your WakaTime Dashboard before exiting. Can be "none" or a positive integer. Defaults to 1000, meaning after sending a heartbeat while online, all queued offline heartbeats are sent to WakaTime API, up to a limit of 1000. Can be used without --entity to only sync offline activity without generating new heartbeats. (default "1000")
--time float Optional floating-point unix epoch timestamp. Uses current time by default.
--timeout int Number of seconds to wait when sending heartbeats to api. Defaults to 120 seconds. (default 120)
--today Prints dashboard time for Today, then exits.
--today-goal string Prints time for the given goal id Today, then exits Visit wakatime.com/api/v1/users/current/goals to find your goal id.
--today-hide-categories When optionally included with --today, causes output to show total code time today without categories.
--verbose Turns on debug messages in log file.
--version Prints the wakatime-cli version number, then exits.
--write When set, tells api this heartbeat was triggered from writing to a file.
Some examples of executing wakatime-cli
:
After sending the currently focused file to wakatime-cli
, your plugin should update the lastSentTime
and lastSentFile
global variables with the current time and currently focused file. This way they will be ready the next time we are handling an event.
Some resources you can use while debugging your plugin.
To confirm your heartbeats are being received, check the plugin status page or the User Agents API endpoint.
If your plugin is working, you should see it at the top of the list. Make sure the editor
, version
, and os
attributes are detected correctly.
Logging errors and info messages from your plugin is a good way to debug problems. Each editor/IDE running your plugin usually provides a log for appending messages. You should setup logging to write there from your plugin and watch it while debugging.
wakatime-cli
has it's own log file located at $HOME/.wakatime/wakatime.log
. To turn on verbose logging, pass the --verbose
argument to wakatime-cli
. With the --verbose
flag, wakatime-cli
will write DEBUG messages to the $HOME/.wakatime/wakatime.log
file.
After your plugin is sending heartbeats, publish it to the world so others can use it too.
Keep track of your plugin's version number with Semantic Versioning.
Send your plugin's version number and name to wakatime-cli
with the --plugin
argument.
Put it on GitHub, send us your repo, then we’ll add it to the Community list.
Even better, transfer the repo to username alanhamlett
and we’ll list it as an official plugin on the WakaTime home page and the official plugins list at https://wakatime.com/plugins. You’ll be given GitHub Maintain access on the repo after transferring.
Finally, consider adding a Buy Me a Coffee or Patreon badge to your repo’s README.md
before transferring the repo.