MACRO: Get Recently Run Macros with Last Executed Time

MACRO: Get Recently Run Macros with Last Executed Time

UPDATED: v1.1 - Added Attribution, as requested.

Get Recently Run Macros.v1.1.kmmacros (4.9 KB)


I love a challenge. :slight_smile:


Hey Dan,

Please remember to add some form of attribution, so we know who to bow to…



OK, how 'bout a readable output format, as in “text columns” LOL
BTW, IMO, a better date/time format is ISO: 2016-07-06 01:43

Thanks, Dan.

1 Like

I keep my macros sorted by Date Used.

This is not only good for finding those that have been recently used, but it can also help when reviewing a particularly complex macro that calls others—you can watch them pop to the top of the list in real time as they are executed.

Done. I was tired.

Knock yourself out. Feel free to modify it however you want. :stuck_out_tongue:

Good idea. The purpose of this macro is that it shows the actual time they were used. It helps when trying to narrow down issues.

Very handy. Thanks for sharing.

Thanks for building that. It’ll come in handy.

1 Like


Thank you for this. Is there a way just to get the name of the last executed macro by the user and pass that as a KM Variable?

It is, but I’m not sure how reliable it would be.

If you have any macros on a timer, there’s no guarantee they won’t end up as being the last macro run.

Also, if you’re like me and have reassigned keys using KM, you may not even realize you just ran a different macro.

You sure still you want it?

1 Like

Yes please :slight_smile:

I am Much obliged.

Put this in an "Execute JavaScript" action, and have it set the results to whatever variable you want to use:

(function() {
    'use strict';

    function getKMStatsFileName() {
        var app = Application.currentApplication();
        app.includeStandardAdditions = true;
        return app.pathTo(
            'application support', {
                from: 'user domain'
        ) + "/Keyboard Maestro/Keyboard Maestro Macro Stats.plist";

    function getPropertiesAndValues(obj, propertiesOnly) {
        var propNames = Object.getOwnPropertyNames(obj);
        var list = [];
        for (var i = 0; i < propNames.length; i++) {
            var propName = propNames[i];
            var propValue = obj[propName];
            if (!propertiesOnly || typeof(propValue) !== "function")
                list.push(propName + " = '" + propValue + "'");
        return list.join("\n");

    function readPlistBinaryFile(filePath) {
        var data = $.NSData.dataWithContentsOfFile(filePath);
        return ObjC.deepUnwrap(
                data, $.NSPropertyListBinaryFormat_v1_0, 0, null));

    function convertStringToPlist(str) {
        return ObjC.deepUnwrap(
                $(str).dataUsingEncoding($.NSUTF8StringEncoding), 0, 0, null));

    function getAllKMGroupsAndMacrosPlist(kme) {
        var _kme = kme || Application("Keyboard Maestro Engine");
        var _macros = _kme.getmacros({
            asstring: true
        return convertStringToPlist(_macros);

    function plistTimestampToDate(timestamp) {
        var result = ObjC.unwrap($.NSDate.dateWithTimeIntervalSinceReferenceDate(timestamp));
        return result;

    var _groupsAndMacros = getAllKMGroupsAndMacrosPlist();
    var _statsPlist = readPlistBinaryFile(getKMStatsFileName());

    var _macroStats = [];
    for (var i = 0; i < _groupsAndMacros.length; i++) {
        var group = _groupsAndMacros[i];
        if (!group.macros) continue;
        for (var j = 0; j < group.macros.length; j++) {
            var macro = group.macros[j];
            var statsDict = _statsPlist[macro.uid];
            if (statsDict) {
                var timestamp = statsDict.LastExecuted;
                var date = plistTimestampToDate(timestamp);
                _macroStats.push({ macroName:, lastExecutedTimestamp: timestamp, lastExecutedDate: date });

    _macroStats.sort(function(a, b) {
        if (a.lastExecutedTimestamp < b.lastExecutedTimestamp) {
            return 1;
        } else if (a.lastExecutedTimestamp > b.lastExecutedTimestamp) {
            return -1
        } else {
            return 0;

    return _macroStats[0].macroName;

I'm sure this could be optimized, but this will work for now.


Thank you very much

1 Like

The code provides the last executed macro, is there a way to get the last executed macro that was selected on the macro palette is this possible?

Possible, but not easily.

Here’s how you might do it yourself:

  1. Take the original macro, and store the value to a variable. Perhaps write the variable to a file.
  2. Somehow filter the result, looking only for the macros you care about.

But you’re on your own for actually doing the above steps.

Hi, if I put an action into a macro. Everytime I run that action I would like it to save the name of the macro that the action is in as a variable. How can I do this?

I would later need to use this variable in an applescript.

From the Wiki:

The %ExecutingThisMacro% token returns the name of the macro the action is within.

So, set a variable to text, and put %ExecutingThisMacro% in the text box.

Then you can access this variable from AppleScript like this:

tell application "Keyboard Maestro Engine"
  set macroName to getvariable "My KM Variable Name" -- whatever you called the variable
end tell
1 Like

Thank you, can this be done as a simple KM action and not script?

Well, yeah, but, and I quote:

Hence why I showed you how to access the variable from AppleScript.

If all you need to do is use this in KM actions, then just use the token. If you’re not sure about tokens, then I’d suggest you go to the Wiki link I provided previously.

1 Like