Good morning! Update January 7, 2020: This feature is now live ! The API documentation has been added to the wiki and our helpdesk . If you find bugs or issues, please report them here . A new function has been added to the Roll20 API to support custom Token Markers, available on the Dev server now. This information is stored under the campaign node as ‘token_markers’. it can be accessed from the api via Campaign().get( "token_markers" ); This information is read-only. The return value will a stringified JSON array containing an object for each token marker currently in the game. { "id":59, // the database id for the "name":"Bane", // the name (non-unique) of the marker "tag":"Bane::59", // how the token is actually referenced // this will include the id for custom markers, but not // for default markers. "url":"<a href="https://s3.amazonaws.com/files.d20.io/images/59/yFnKXmhLTtbMtaq-Did1Yg/icon.png?1575153187" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/59/yFnKXmhLTtbMtaq-Did1Yg/icon.png?1575153187</a>" // ^the url for the token marker's image } Add this Script to your game and these commands will be available:We’ve written an example script to show how you can use this to find Token Markers available in your Campaign. ! markernames &nbsp;will output all markers to the chat with the image, name and id !markerids &lt;name&gt; &nbsp;will output any/all markers to the chat that match the provided name !settokenmarker &lt;string&gt; &nbsp;will add the provided string to the currently selected token’s marker list. Note that this doesn’t do any validation to make sure the Token Marker exists, it simply adds the provided value to the token markers. !gettokenmarkers &nbsp;outputs the currently selected token’s marker attribute to the chat. on("ready", () =&gt; { const tokenMarkers = JSON.parse(Campaign().get("token_markers")); const getChatMessageFromTokenMarkers = markers =&gt; { let chatMessage = ''; _.each(markers, marker =&gt; { chatMessage += `&lt;p&gt;&lt;img src='${marker.url}'&gt; ${marker.id}: ${marker.name}&lt;/p&gt;`; }); return chatMessage; }; on("chat:message", msg =&gt; { if(msg.content.split(" ")[0].toLowerCase() === '!markernames') { let chatMessage = getChatMessageFromTokenMarkers(tokenMarkers); sendChat("Token Markers", chatMessage); } else if(msg.content.split(" ")[0].toLowerCase() === '!markerids') { const markerName = msg.content.split(" ")[1].toLowerCase(); let results = []; _.each(tokenMarkers, marker =&gt; { if(marker.name.toLowerCase() === markerName) results.push(marker); }); log(results); let chatMessage = getChatMessageFromTokenMarkers(results); chatMessage = chatMessage || 'Unable to find any matching token markers' sendChat("Token Markers", chatMessage); } else if(msg.content.split(" ")[0].toLowerCase() === '!settokenmarker') { const markerName = msg.content.split(" ")[1].toLowerCase(); if (!msg.selected &amp;&amp; msg.selected[0]._type == "graphic") return; obj = getObj(msg.selected[0]._type, msg.selected[0]._id); currentMarkers = obj.get("statusmarkers").split(','); currentMarkers.push(markerName); obj.set("statusmarkers", currentMarkers.join(',')); } else if(msg.content.split(" ")[0].toLowerCase() === '!gettokenmarkers') { if (!msg.selected) return; if (msg.selected[0]._type !== "graphic") return; obj = getObj(msg.selected[0]._type, msg.selected[0]._id); currentMarkers = obj.get("statusmarkers"); sendChat("Token Markers", currentMarkers); } }); }); Your Feedback is Wanted Your feedback is greatly wanted with this update! Please post your feedback in the main thread in the Pro Forum here .