This tutorial will show you how to create your own Sidekick script.

Getting Started
Basics and Planning
With previous versions of WM, the sidekick just processed the bonuses it was told to. But now, sidekicks also contain all the information needed to identify those bonuses and create Options Menu entries for WM. Those options and "definitions" are then passed to the main WM script when it "plugs in". Here is a starter list of things you will need to build your new Sidekick.
Facebook App ID
Facebook issues an app ID to each app that gets created, even those underhanded scam apps. This app ID identifies a post as coming from that app.

When WM runs, it collects posts and labels them based first on the post's app id.

To find a post's app ID, there are many things you can do:

  • Examine the via <game name here> link using either FireBug or Google Chrome and look for an appID parameter or something similar
  • Examine an image location href from the game and check for an appID parameter
  • Search Google for an appID related to the game. I guarantee you somebody already made this information public.
Bonus Types
You really should strive to maintain a comprehensive list of bonus types for the game this new Sidekick supports. Nobody wants a half-assed bonus collector that only collects coins, but not other resources.

You should be an avid player and know where to get all kinds of info about a game, especially new content. Wiki sites are a great place to search. Some games even have breaking news sites made by fans, such as FrontierVille Legend.

Create a list of all the bonus types, and even go into depth of how many of each bonus item can be obtained from that bonus, especially if higher numbers make a substantial difference in the game. Here's an example list:

  • 500 coins
  • 250 coins
  • 100 coins
  • 50 coins
  • 100 xp
  • 50 xp
  • 25 xp
  • 10 xp
  • Fire
  • Wood
  • Send Nails
  • Send Wood
Definition List
Next you need to figure out what posts link up to which bonus types. Many games simply say "get a bonus" in the link text, leaving the user in suspense. However, bonus collector users don't want to just "get a bonus", they want to know what that bonus is so they can determine if its even worth getting.

The WM script has many built in search methods, but here are the main 4:

  • Body Text: Searches the text from the post title all the way to the comments section
  • Link Text: Searches just the text in the link to get a bonus
  • Link URL: Searches the url inside the link for specific code
  • Body HTML Code: Searches the html behind the post from the title to the comments section

You can make use of all these function to identify a post. Below are examples pulled from various games:

  • In FrontierVille, the body text "is blowin' up the woods" to date always provides a "Powder Keg" item.
  • In Ravenwood Fair, a link url containing "quest_rosepetals" always sends a "Rose Petals" item.
  • In Empire and Allies, most link url's containing "frType=Q" followed by anything provide "25 coins".
  • In CityVille, any link text that says "go play cityville" normally takes us to the game without a bonus, so we call that an "exclude" link (more about the "exclude" magic word later)
  • In Ravenwood Fair, to date, any post that contains an image "remindFriend.jpg" is also not a bonus link and needs to be excluded. We search for that using the body html.

You just need to find as many of these matches as possible. Good complex games will have huge lists that are ever expanding. Some simple puzzle games may have 10 or fewer bonus types.

Be absolutely sure your definition is sound. It should not contain a single word that might represent multiple types of bonuses. For instance, we do not check FrontierVille posts simply for the word "wood" and expect wood every time. The word wood could get wood, send wood, give a wooden post, or be some other reference altogether.

If at all possible, always use 5 letter words or greater. Four letter words or smaller are often a substring of a larger word. For instance, we never search for the word "hat" to define a post. The words: what, that, chat, etc. will always get captured as a "hat" if they come before another search term you have defined.

Be very specific, even if that means a whole sentence to identify each bonus given.

Luckily, many games are now using post defining text right in the link url. For games such as Ravenwood, Ravensky and CityVille, we can simply look for a certain parameter in the link url and that code will always exist no matter what language the poster uses. Via this method, we can bridge the language barrier without much effort. But don't expect every app to be so easy to bridge.
The Harder Stuff
Let's start with easy-hard stuff and work our way up to hard-hard stuff. Yes there is much more to a sidekick than definitions. Here's a list of stuff you need:
  • The URL location or locations of bonus acceptance pages
  • Acceptance message text
  • Failure message text
  • Common errors and their text if any

So let's get started on these shall we?

Acceptance Page URL
It is very important to know the location of the acceptance page, since that is where the sidekick will do its magic. Below is an example URL for FrontierVille:
  • http://**

The URL has been truncated so it only includes the part we care about. Asterisks are added where data is not useful. In this example, reward.php is the document that processes your request for a bonus or to send something, and also displays the acceptance page to your browser. Anything after that URL section usually pertains to the bonus, and we already know most everything we need to know about the bonus at this point.

Some games such as CityVille and CafeWorld have multiple pages, each designed to provide or send a different kind of item or bonus. You need ALL the URL's for these pages if your sidekick is to work properly.

To determine these page locations, you cannot just read the URL in the address bar. Many games now use iframe objects to display messages you will want to read with your sidekick. I highly suggest getting the extension called FireBug for FireFox. This extension allows you to see the tree structure that is the document DOM. If you don't understand DOM, go read up on it using Google or W3Schools. It will be important for you to know, especially if the game you create a sidekick for changes iframe locations frequently.

Now, assuming you understand DOM structure, you can now use FireBug to examine that DOM structure:

  • You will want to right click on the text messages you see in the acceptance page and "inspect element".
  • A panel will come up from the bottom of the screen and have sections of its own. The section you will want to use is on the lower right and has tabs, such as STYLE, COMPUTED, LAYOUT and DOM. Click DOM.
  • In the DOM sub-panel you will see a treeview list of the element's properties. These properties are in alphabetical order (generally speaking, as functions appear first in green text).
  • The most useful attribute I can suggest is the baseURI. Alternately you could traverse the tree structure and pull up the ownerDocument.location.href attribute.
  • Copy the URL in that attribute and paste it somewhere useful, or just write it down.
Acceptance and Failure Message Texts
Once you know the acceptance page URL, you can easily ask that page if it contains certain text. The text we need to find is either an acceptance text, failure text, or anything we know is returned when an error occurs, including errors caused by Facebook instead of the game.

Here's an example of acceptance text from FrontierVille:

  • "All Outta Rewards"

A word of caution: This text is most often printed directly by the acceptance page URL and the sidekick can easily return it to the main WM script. However, some games like Ravenwood Fair, print their failure messages from another address, inside an iframe with a different domain (see previous section).

Collect ALL of the texts you can find and match them up with the following return codes:

  • 2:"Responseless Collection", normally handled inside WM host
  • 1:"Accepted"
  • -1:"Failed", use for reason unknown
  • -2:"None Left", use for reason of already taken
  • -3:"Over Limit"
  • -4:"Over Limit, Sent One Anyway", registers as a type of acceptance
  • -5:"Server Error"
  • -6:"Already Got", registers as a type of acceptance
  • -7:"Server Down For Repairs"
  • -8:"Problem Getting Passback Link", used only with special flags
  • -9:"Final Request Returned Null Page", normally handled inside WM host
  • -10:"Final Request Failure", normally handled inside WM host
  • -11:"Expired"
  • -12:"Not a Neighbor", neighbor-ship required to accept post
  • -13:"Requirements not met", level or building requirement
  • -15:"Unrecognized Response", prevent waiting for timeout if you know to watch for some known issue
Building a Sidekick Script
If you comprehend anything at all to this point, you are ready to jump into the code. So let's go!

GreaseMonkey takes the sidekick script as JavaScript, attaches it to the page its meant for, and then runs it as soon as that page calls an "onload" event. You don't have to do anything to start the code except provide the acceptance page urls in an @include section on top of the JavaScript file. If you are NOT new to user scripts, this is going to be easy. If not, I bet you have no idea how to write JavaScript anyway and you should be reading a JavaScript tutorial instead.

  • See [ W3Schools] for a really nice starter.

A sidekick script generally has 3 parts:

  • A userscript header block
  • A docking function
  • A reading function
User Script Header Block
Since it is really short, lets look at a header block from the Heroes of Neverwinter sidekick:
// ==UserScript==
// @name           Wall Manager Sidekick (HoN)
// @description    Assists Wall Manager with Heroes of Neverwinter
// @include
// @include*
// @include*
// @license
// @version        0.0.6
// @require
// @copyright      Charlie Ewing
// ==/UserScript== 

The above block is the user script header block. When this file is read it is automatically picked up by the script processor, in this case GreaseMonkey. The lines tell the script how to behave, and especially where to execute.

This block for HoN only includes two URLs for bonus collection. The includes are specific statements to help it dock with the WM script. If you change or remove the includes it may not work correctly.

You can make your sidekick script automatically update for any user by including the @require line with the url above. After you post your script to, your script is registered with a script ID. Change the id= parameter in that line to the id of your script, and then upload to userscripts again. Failure to change that id will cause your script to attempt to update THIS script.

For the most part, this code segment is self explanatory, but if you need more info, please use Google to figure it out. There is plenty of info out there on how to make user scripts, but this page is about how to make sidekicks for those who already understand user scripts.
The dock() Function
The dock function does just that, tries to dock with the WM host script on the launch page. This function contains all the info the script needs to identify, open, and collect bonuses for the supported game. All that info gets attached and assimilated into the WM host script when it properly docks.

To properly dock with the WM host script, a sidekick needs the following data:

appID (string)
The app id we determined earlier.
synAppID (optional array)
An array of any other appID's that count as the same game, or as a sibling game or tie-in.
name (string)
The actual name of the game this sidekick is for as it will be displayed in the options menu.
desc (optional string)
A short description of what your script will do, or the multiple games it works on, etc. No HTML please.

If left blank, the desc parameter defaults to:

  • <app name nere> Sidekick (ver <version number here>)".
icon (optional string)
A URL that points to an icon that represents your sidekick. Please no porn. Thanks much.
thumbsSource (optional string or array)
A URL section where all news feed images for this game come from. For instance, Empires and Allies images are located at "". The WM script finds images that contain this snippet and deletes them when that option is enabled in the menu.
  • Many games on Facebook use the same image proxy and you might be able to just supply "app_full_proxy.php?app=" + your appID. An empty thumbsSource parameter will now default to this value.
flags (optional object)
This is reserved for special flags. Some games behave in strange ways and some code may need to be appended to the WM script to process them correctly when for some reason a sidekick cannot. Current flags that exist are:
httpsTrouble (bool)
This is used for when a game is known to load stuff in https mode, preventing bonus collection in a normal way.

Setting this to true causes the main WM script to behave differently when it checks that a bonus page has loaded.

This flag should also be set if the game you are collecting for is not an apps.facebook hosted game. Non-facebook apps that post to facebook draw the user off-site and the sidekick will not be able to return information to the main script body normally.

See also the flag skipResponse for dealing with some off-facebook apps.
requiresTwo (bool)
This is used for games such as PT and CW where a link must actually be clicked to get a bonus.

Because the bonus collection page info may be lost if the sidekick did this clicking, we pass the info back to the WM script for processing. Setting this to true activates another part of the WM script.

Most games don't need to worry about this, and clicking their links or buttons via the script is just fine.
alterLink (bool)
This is used for games such as FV where a link needs to be modified before it is processed so that the destination page is more useful to this script. For instance, we modify some links that take us to the gift sending page for FV so that only one resource exists to choose from.

Other games such as MouseHunt have an apps.facebook page and a non-facebook page. Some links take you off-site and will cause cross-domain errors, so forcing them to stick to their apps.facebook version is helpful.

Not many games can benefit from this option.
skipResponse (bool)
You can use this flag to cause your sidekick to ignore return values. Instead, the main script body will just look for load status on the sidekick window.

When the status checker thinks it has found a fully loaded page in the sidekick window, the status will become "status: 2: responseless collection". All status 2 urls are stored as accepted.

  • Not all load statuses are accurate, so not every page marked as accepted will be correctly accepted.

I suggest using this flag for games where the user has 100+ bonuses to collect per day and no limits. Using this flag can make bonus collection much faster because some steps are omitted. Again, this is a very inaccurate method of collecting bonuses, and every attempt should be made to try other methods.

  • You cannot use skipResponse with games that also need the "requiresTwo" flag.
  • You cannot use skipResponse with games that have a bonus collection page that requires another click to accept or decline a bonus type
alterLink (optional object)
This is a JSON object containing the four following parameters:
  • Note: current versions of standard and beta WM both accept an array of alterlink objects, but can still accept a single object
find (string)
The text to find in the link url. This parameter can convert to a RegEx using the following "isRegex" parameter.
isRegex (optional bool)
Converts the find string into a RegEx with no modifiers.
replace (string)
The replacement text for the link url.
dataSource (string)
New in WM3beta35 and WM2.2.6.0: this parameter lets you choose which portion of the post to search for entries in the words array (below). Previously, alterLink only had access to the 'either' post part, which was the combination of caption and body. You can now choose from more options, including many (but not all) of the parts available to dynamic grabber or rules manager. If no dataSource is provided, WM defaults to using 'either'.
words (optional array)
A list of words that can be found in the post body to determine the changes needed in the link url. This begins a second function of the find and replace combo. By setting the find parameter to something containing {%1}, it will search the post body for all the values in the words parameter until one is found. It will then convert the link url to include a block of code from the "conversionChart" parameter below, using the found word as an index into that chart.
conversionChart (optional object)
A set of word to item code associations. For instance, one entry for FV would be "shovel":"shovel_item_01" where "shovel" is a string in the "words" array and "shovel_item_01" is the code for 2 shovels on the FV gifts page.
  • See the FV sidekick for a better look at alterLink use. That sidekick makes excellent use of the alterLink ability by pre-selecting 1 to 3 items from the gift page depending upon what post sent the user to that gift page.
  • This is only activated when the flags object (above) contains the parameter alterLink:true.
accText (object)
is a JSON object containing a list of bonus types and their plain english translation.

Here's an example from the EA sidekick:

  • coins10:'10 Coins',coins25:'25 Coins',coins50:'50 Coins',energy:'1 Energy'
tests (array)
An array of JSON objects used to define a bonus type. Each test object in the array contains a test text and a return value.
  • Test search texts are NOT case sensitive, however return values ARE.
  • You cannot currently use these tests to specifically find uppercase text or the lack thereof.
  • Return values must exactly match those in your accText section above, and also those in your "menu" object below.
Test Regions
Tests can be in the following forms, and are case sensitive:
  • link: the test is run on the link text
  • url: the test is run on the link url
  • body: the test is run on the body text of a post, which includes the following: title, caption and desc(ription)
  • title: the bold text on top of a post. Does NOT include the msg portion.
  • caption: normal text below the title, not all games use this. See also desc
  • desc: normal text below the title, not all games use this. See also caption
  • html: the test is run on the whole post contents. In WM 2, this is not actually the html of the post, but a jumble of all the other searchable sections of the post.
  • either: you can do both the link test and the body test in the same line, in that order.
  • msg: you can test for text in the message portion of the post. The section above the post where users can add their own text. This is NOT included in a body search.
  • img: the url for the image that goes with the post. Not all posts use this field. Mostly that is a mistake on the part of the game engine to attach one to the FB database.
  • fromName: the name of the person who created the post case. sensitive as fromName
  • fromID: the id of the person who created the post. case sensitive as fromID
  • targetName: the array of people the post targets, name form.* case sensitive as targetName
  • targetID: the array of people the post targets, id form.* case sensitive as targetID
  • canvas: the location on facebook where the game runs, for instance farmville="onthefarm"
  • likeName: the array of people who like the post, name form.* case sensitive as likeName
  • likeID: the array of people who like the post, id form.* case sensitive as likeID
  • comments: the text of all comments attached to the post
  • commentorName: the array of people who commented on the post, name form.* case sensitive as commentorName
  • commentorID: the array of people who commented on the post, id form.* case sensitive as commentorID
(*) Does not show id's of people who block non-friends from seeing their activity.
Test Examples
Since the WM's internal makeup has changed a lot over the last year, I will go through a bunch of ways you can use to identify posts.
  • Using relic methods to create a test:
  • {url:"frType=Q", ret:"coins25"}

Searches the link url for "frType=Q" and returns "coins25" if found

  • Using current methods to create a test:
  • {search:"url", find:"frType=Q", ret:"coins25"}

Does exactly the same as above

  • Using an array to create a test searching multiple post parts:
  • {search:["link","body"], find:"send", ret:"send"}

Searches the post link text for "send", and if found returns "send". If not found, it then searches the post body with the same results.

  • Using an array to create a test searching for multiple words:
  • {search:"link", find:["lunch","breakfast","dinner"] ret:"meal"}

Searches the post link text for lunch, breakfast or dinner, and if found, returns "meal".

  • Using two arrays to create a test searching for multiple words in multiple search regions:
  • {search:["link","body"], find:["lunch","breakfast","dinner"] ret:"meal"}

Searches the post link text for lunch, breakfast or dinner, and if found, returns "meal", and if not found, performs the same search on the post body.

  • Using a subTest array to identify multiple post types:
  • {search:"link", find:"{%1}", subTests:["lunch","dinner","breakfast"], ret:"{%1}"}

Searches the post link text for breakfast, lunch, or dinner and returns the word found.

  • Using a subTest array to identify a single post type:
  • {search:"link", find:"{%1}", subTests:["lunch","dinner","breakfast"], ret:"meal"}

Searches the post link text for breakfast, lunch, or dinner and returns the word "meal".

  • Using a subNumRange to identify multiple post types:
  • {search:"body", find:"level {%1}", subNumRange:"1,20", ret:"getlevel{%1}"}

Searches the post body for the word "level" followed by any number in the range from 1 to 20 and returns "getlevel" followed by the number found. Numbers are run from highest to lowest to prevent "level 10" from being identified as "level 1".

  • Using a subNumRange to identify a single post type:
  • {search:"body", find:"level {%1}", subNumRange:"1,20", ret:"getlowlevel"}

Searches the post body for the word "level" followed by any number in the range from 1 to 20 and returns "getlowlevel" no matter what number is found.

  • Using a registered expression to identify multiple post types:
  • {search:"link", find:"(black|white) (pony|horse)", regex:true}

Searches the post link text for any combination of black or white, pony or horse, and returns whatever matches first

  • Using a registered expression to identify a single post type:
  • {search:"link", find:"(black|white) (pony|horse|bear|cat)", regex:true, ret:"adopt"}
Searches the post link text for any combination of horse, pony, bear or cat, preceded by either black or white, and returns "adopt" no matter what is found.
The new search(string or array) and find(string or array) parameters
Since version 2.1, WM can make use of the search parameter instead of supplying search:test pairs such as url:string, or body:array.

Now you can say:

  • search:region string, find:string
  • search:region string, find:string array
  • search:region array, find:string
  • search:region array, find:string array
See examples above.
Searching Multiple Sections of a Post
Tests can accept arrays in the search parameter.

Remember arrays are searched in the order supplied. If you pass an array to your test object, be sure it is ordered in the way you want the searches to be performed.

See examples above.
Supplying Arrays as Tests
Tests can accept arrays in the testing parameter (ie. link, body, url, html, etc. or the new find parameter). This version of the test does not have any ability to return multiple values like the subTest array (see below). Use it to grab multiple texts that represent the same return value.

Remember arrays are searched in the order supplied. If you pass an array to your test object, be sure it is ordered in the way you want the searches to be performed. For instance if your array contains "pea" before "peanut", it will find "pea" in the word "peanut" before finding the word "peanut".

If you include the WM Library Script in your sidekick, you can call the optimize method on your array as you pass it to the test object, like this: {search:"body",find:"{%1}", subTests:myArray.optimize(), ret:"{%1}"}

See the WM Library Script documentation for details.
Finding multiple words using the subTests (array) parameter
Sidekicks make use of the subTests parameter which takes an array of strings. These strings can be fitted into both the find parameter and the return value of each test. Use the string "{%1}" in your find string and your ret parameter string as an insertion marker.
  • Example: {body:'needs {%1}',ret:'send{%1}',subTests:["rope","rock","nails"]}

In the example above, the test searches for body text containing "needs " + an array item from subTests. The test process tests in order of appearance, returning the first found value. The above example would test for "needs rope", then "needs rock" and finally "needs nails".

To optimize a subTest array, you must understand and implement the following:

  • Arrays are read in order, thus an entry that starts with some string X must come before a string that is simply X. For instance, "popcorn" must come before "corn" or "corn" will be returned if a test string looks like this: "{%1} bushels".
  • The same is true: "cornflower" must come before "corn" or "corn" will be returned if a test string looks like this: "send {%1}".

Depending on which value is found, the return value is then altered where the same {%1} appeared. The example above could return "sendrope","sendrock" or "sendnails".

Like the find string, subTest strings are not case sensitive. But since return text is sensitive, when inserting {%1} back to the return text, the search text is converted to lower case and has its spaces removed. For example, if "Energy Pack" was supplied in the subTests array above, the return value would be converted to "sendenergypack".

You can also omit the {%1} from the return value to return the same value for each subTest.

  • Example: {body:'needs {%1}',ret:'sendmaterial',subTests:["rope","rock","nails"]}

You can also create and then provide a predefined array. This is handy when you need to use the same list more than once.

  • var arrayExample = ["rope","rock","nails"];
  • ...
  • {link:'send {%1}',ret:'sendmaterial',subTests:arrayExample},
  • {body:'needs {%1}',ret:'sendmaterial',subTests:arrayExample}

The examples above always return "sendmaterial" if the body text contains "needs rope", "needs rock" or "needs nails", or if the link text includes "send rope", "send rock" or "send nails".

The subTest parameter is exceptionally useful when many bonus types are awarded using the same basic text layout. Say you have 100+ bonus types and the bonus text appears like this:

  • "wants to share a {%1} with you in FarmVille", where {%1} could be any bushel crop, a manure bag, or some other gift.
Performing a number search using the subNumRange (string) parameter
This parameter can be used to replace the subTests array with a range of numbers. Specify a range such as 10-20 as "10,20".
  • Example1: {body: "level {%1} sample" ,subNumRange:"1,20", ret: "samplelow"}.

This would search for any text from "level 1" to "level 20" and return "samplelow" if found.

  • Example2: {body: "level {%1} sample", subNumRange:"1,20", ret: "sample{%1}"}.
This would search for any text from "level 1" to "level 20" and return "sample" followed by the number found, such as "sample5".
Registered Expression Usage and the regex (bool) parameter
You can use registered expressions (regex or RegExp) in the testing process. To do so, you must set the regex parameter to true. You also have access to a mods parameter which you can use to override the preset "gi" modifiers.

You may either use a return value, or by default, the test will return what is matched by the regex. Become familiar with RegExp before attempting this method.

You cannot supply an actual registered expression as a test because a registered expression is an object, and a sidekick cannot pass complex objects back to the WM host script. This is why you must supply it as text and then have WM convert it for you once docked.

Below are some examples:

  • Example1: {body:"(turkey|chicken) (feed|poop)", regex:true}

This would search for turkey feed, turkey poop, chicken feed or chicken poop and return what was found.

  • Example2: {body:"(turkey|chicken) (feed|poop)", regex:true, ret:"material"}

This would search for turkey feed, turkey poop, chicken feed or chicken poop and return "material".

  • Example3: {body:"(turkey|chicken) (feed|poop)", regex:true, mods:"g"}
This would do the same as the first example AND change the modifiers for the match to just "global" removing the case insensitivity. Remember, that would be bad because the case of every part of the post is put into lower case. Defaults are "gi", global search and case insensitivity, and you might want to keep them that way.
Magic Words
Tests can return the following magic words:
  • exclude: Excludes the post from being processed. Note that "exclude" does not start with your game's appID after joining with the WM host script. Use exclude when you want to block a post, especially those meant to lure you to the game without a bonus being given, or for bonus types you don't know how to collect yet and you don't want the "doUnknown" magic menu option to collect on accident.
  • wishlist: A type of exclude, except that posts flagged as wishlists can opt to not be hidden with excluded or other unwanted posts. This allows users to click the wishlist posts from WM and process them manually.
  • send: A short word that can be picked up by the "sendall" magic menu option. This is useful if the sidekick does not need to know what its sending, or the user would simply not benefit in knowing that information.
  • dynamic: This word will flag the post as being grabbed by the dynamic grabber, even though its being identified by your sidekick. Posts flagged with "dynamic" are simply processed as if an option was checked for their type. There is no options to disable or enable the collection of posts flagged as "dynamic". This is also the default return value given by any user created dynamic test that does not supply a ret parameter.
Note(string) and other "unused" parameters
Tests can have any number of other parameters, most of which will have no effect on the WM or its behavior. A sidekick creator can inject a test with any number of these parameters if they wish to store notes for themselves, or if their sidekick performs special transformations on tests before passing them to the WM dock.

One such parameter could be the note parameter. Take special care when leaving notes for yourself in the note parameter as the WM does actually read and use that parameter when identifying posts using user-created dynamic tests. In fact, there is a tab in the dynamic grabber console for each test which shows the note field's contents.

All other parameters unrecognized by the dynamic grabber console are shown on the "Other" tab in the order they appear in the test object.
menu (object)
Another JSON object in the form of a menu tree. Menu items each correspond to a definition from accText above. If the WM script finds a test that matches a checked menu object, that bonus is processed. Menu items must match exactly to those in the defining test and accText sections or bonuses will not be properly collected.

For an example on how to build a menu object, simply view the source for any of the supported Sidekicks, or the Sidekick Starter Kit below.

Menu items can exist in the following types:

Defines a closeable section with gray header bar. This should only be used once per sidekick (or once per major function if a sidekick does more than one major thing). Section uses the following other parameters: label,kids,title. Section objects are stored as a variable and remember their open/closed state when you next enter the options menu.
Defines a closeable segment similar to "section" elements, however the bar is blue and it also displays select all/none buttons on the right. Add the parameter hideSelectAll:true to the separator element to disable display of these buttons. Separator elements can be nested inside each other, providing different closeable levels. Future versions may offer a bar color for each depth. Separator uses the following other parameters: label,kids,hideSelectall,title.
  • Separator objects are stored as a variable and remember their open/closed state when you next enter the options menu.
Defines a closeable tab that acts as a container just like a "section". There is no need to define a tab container, as the tab element automatically negotiates its position and locates siblings. Tab uses the following other parameters: label, kids, title.
  • Tab objects are stored as a variable and remember their open/closed state when you next enter the options menu.
  • New tabs which the user has not used before may not have a selected tab, causing the tab bar to look like it has no panels. Selecting a tab cures this anomaly.
  • A CSS issue currently prevents tabs from using the newitem special parameter. A future version will remedy this issue.
Defines a selection group, containing the objects in its "kids" parameter as sub elements. It also automatically creates a select all and select none button set for the block. You may add a parameter hideSelectAll:true to the optionblock to disable display of those buttons. Currently the text is a bit small on the block label, but it will be changed. Optionblock uses the following other parameters: label,kids,hideSelectAll,title.
Defines an actual option. Checkbox uses the following other parameters: label,title,"default",newitem.
Creates a link. Link options are always opened in NEW windows or tabs, not the window running the WM script. Be sure to include an href:"your url here" parameter in the link declaration or it wont do much. Link uses the following other parameters: label,href,newitem,title.
defines an actual option in a group where only one can be chosen. Radio uses the following other parameters: label,options,newitem,title.
Defines an option but it does not appear on the options menu. Use this to hide default options that you wish to modify later, or per version options you don't want users to change yet.
Defines an option as a textbox that the user can fill in. Accepts the following additional parameters: cols, rows, title, label,"default".
Defines a group of options as a multiselect box. Select uses the following other parameters: label,options, title,"default"
Creates a button that when clicked highlights an array of elements. Use the "options" parameter to provide that array of elements. Elements in the array are strings that match EXACTLY a defined option.

A second array can be provided in the "clearfirst" parameter and when clicked, the button function will first un-highlight the provided array of elements. You may omit the options parameter to create just an unselect button.

This element also takes the title and label parameters.
Creates a button that when clicked selects an array of elements. See button_highlight above for further details, including the "clearfirst" parameter.
Creates a button that when clicked selects all elements that begin with the given prefix parameter. Unlike other buttons, you do not supply an array in the options parameter. Instead this button fetches its own data. Also there is no clearFirst array parameter. Instead, use the clearPrefix parameter to create an unselect button for a prefix of elements.

As an example, imagine there are 200 animal adoption links, of which you script every one to have an id prefix of "adopt_", and of which 20 are deer and you prefix them with "adopt_deer", where the rest of the id is the color or name of that deer type, such as "adopt_deermule". If you put all the animal adoption options in one optionblock, you would only be able to select that entire block, or single items at at time. But now using the "button_selectprefix" type with a prefix parameter of "adopt_deer", only the deer in that option block will be selected.

This button's function will select ALL options from the options menu for your appID that match the prefix given, even outside the option block, or section you enclosed it in. This allows for selecting of multiple elements from multiple groups of which you provided the same prefix. For instance you may have a group of elements scattered through your options menu that are all somehow related, but generally of different types. You could code them all as "silo_part", "silo_animal" or "silo_reward". Then you could make a button to select anything prefixed by "silo_".

Remember the selectall magic menu option already does something like this without actually checking options. You could duplicate this function by making a button with prefix "send". Remember also that items coded properly as a send function will be prefixed by "send". In the example above, if you created an element with id "sendsilo_part", a button with prefix "silo_" would NOT select that bonus type.
Defines an option as a text box. Be sure to set the parameter "size" or it will default to 25 characters. Text uses the following other parameters: label,title,size,"default". Alternately, you can specify the element type as "float" or "int" to create a number box rather than a text box. It does not prevent letter characters from being entered, but it does change how options are used and stored.
If type is not supplied, type defaults to "checkbox".
Because WM does not allow sidekicks to pass functions, "button" menu items will not have any onclick functions set to them. This is to protect WM users. For built in button functions, see "button_selectmulti" and "button_highlight" above.
Special Parameters
Each menu object element can accept the following special parameters:
If newitem is set to true, most elements take on a green background color. Use this to point out a new item to users. Be sure to remove it on the next update.

If your sidekick needs more than one highlight color, you can opt to set newitem to 1, 2 or 3 instead of just setting it to true. These numbers correspond to green, dark red and royal blue. The value true corresponds to a more lime green color.

These colors are hardcoded in the WM host script, but can be edited by installing a secondary script on the host page which replaces certain CSS code. Ask me if that is something you want and I will show you.

If you do really want other colors, see the backgroundColor and fontColor special parameters below.

As of some early WM3 beta versions, newitem also carries with it a counter which is passed up the menu tree and will be counted in each parent branch. This makes a trail showing users where all the newest items are located.
This parameter takes any type of color value you can pass to CSS style. That can be CSS color words, hex RGB values in #RRGGBBAA format or sans the AA, and also CSS functions that return CSS color values, such as RGBA(###,###,###,###) or just RGB(#,#,#). This parameter changes the background color of the DOM element in which the text is located for most elements, but can be used on any element type available in the sidekick menu system. Results vary by element type.
Changes the font color of the menu item. See backgroundColor above for details on usage. This is more specific and useful than newitem, but does not show a newitem counter in menu headings. You can use them together.
Give any menu item a parameter of startDate and/or endDate and it will be omitted from the displayed options menu if the current time on the user's computer is NOT within that time range. If either is NOT supplied, the date is open ended in that direction. Naturally, omitting both lets the menu item display every time. Use this feature to create menu stuff for items you know will be coming up in a game, or to limit its display if you know the end time of a special event. You can also set the endDate to a fictitious previous date if you want to hide parts from your menu but still have it. This would basically be the same as commenting out the menu code, with a little more work on the part of the browser to hide it.
Magic Menu Options
The following words can be used to create menu items with special built in functions:
Toggles processing of posts the script can't identify.

To make good use of this, you should always find and define any post you want to "exclude" to keep the game from loading without giving a bonus.

For instance, if the link text "go play" was not excluded, whenever somebody started playing a game, enabling "doUnknown" would click that link and just get taken to the game without a bonus.

  • Note doUnknown contains an uppercase "U".
A super function to toggle sending of all "send" prefixed links. This only works when "send" type links are defined with the prefix "send".
  • Example: send a bucket of water looks like "sendwaterbucket".
If you have 100+ sendable items defined with prefix "send", then "sendall" will enable them all at once. It doesn't click to toggle them, its just an internal override.
This is not a magic option in itself, but you can use it in your menu as long as you also use it in your test techniques.

You can provide the word "send" alone with no item name. To make use of just "send" your sidekick must return just "send" during its test phase, even if the actual item is not fully identified (See PT sidekick for examples). Just "send" is also picked up by the "sendall" magic option.

This becomes useful because even when a send-type post is not fully identified, sendall will still recognize it as a send-type post and will perform collection on that post.
The read() Function
This portion of the sidekick is meant to run only on the bonus delivery page and is the part of your sidekick that reads accept and fail messages.

This part is very simple, but must be able to run in the exact window object(s) where those message will exist.

It might also need to perform some special tasks, such as clicking buttons to finalize collection of a bonus, or even collect a link that the WM host can process behind the scenes so as to prevent this script's function from being canceled out.

Acceptance and Failure Messages
Your sidekick needs to be able to see and read acceptance and failure messages from either the main window, or from a buried iframe.

These messages are what WM has over all the other scripts and apps out there. WM can report back to the user this acceptance, failure, and many other codes that the user can easily understand. Based on these reports, the user can determine if a bonus should have been collected, or whether they should try clicking the bonus again.

Your script should go out of its way to get this information back to the user.

Look for texts that specifically state whether the bonus was collected or not, and for reasons why.

You then want to pass that information back to the WM host script via the window's url. You must return it via that or the WM cannot see it. While the bonus is being processed, the WM is watching that address bar and waiting for your response. When no response is found, WM assumes you can't do your job for some reason and marks it as "timed out".

The WM Library comes with a function to do just that. Use the sendMessage function to pass back a code like this:

  • sendMessage("status="+statusCode);

A list of codes you can return is found above under "The Harder Stuff > Acceptance and Failure Message Texts". These range from positive acceptance codes, to negative failure codes, some of which have special functions associated with them in the WM host script.

Good examples of how to find these messages can be found in any currently supported sidekick script, as well as in the sidekick starter kit script.
Secondary Clicking
You may find that for your targeted app, the game requires you to click another button to actually collect the bonus. And then maybe even another button to verify that you want to bother the person you are helping with a gift.

You need to be able to find, handle and click these buttons using your sidekick. WM cannot do it for you.

The WM Library comes with a few functions to help you locate, grab and also click these buttons.

Depending on what that button does, you may need to make additional @include lines in your script. For instance, if clicking the button takes you to the actual game load page, you need to include that page's url in your script header block. Your script will then fire there too, and allow you to finally report back acceptance or failure from that location rather than the initial location your script fired at.

This is actually much easier than it sounds. See the various supported sidekick script for different examples.

Occasionally, you will encounter popups from facebook. These popups, as of the time of writing this, come from the facebook dialogs widget, and are currently part of facebook's "Frictionless" system. While the system does initially cause some friction, you should only ever have to deal with this widget once per user per app. All other posts you click to interact with this same person slip past the widget as previously approved.

To interact with the widgets, you may need to include some facebook url's. Be very specific or your script will run on every instance of these widgets, even for other apps. Also be specific in your coding to ensure that you are actually running within the bounds of your target app. Most instances of these widgets come complete with a url parameter defining the appID the widget is requested for. But don't rely on that alone. The widget also makes use of a form element and you can check the action of that form and block certain actions.

For example, many games use the frictionless widget for requesting neighbors. Most of those games use a location document of neighbors.php. You can check that the action of the form containing the target button does not point to neighbors.php. Otherwise all hell will break loose.

As an example of the mayhem lax @include statements can cause: In mid January of 2012, Farmville changed their neighbor adding page and made use of that widget. Due to similar changes in the FV sidekick, the combination of includes and the location of the facebook widget caused the FV sidekick to mass add neighbors and mass send gifts at the same time without requesting permission from the user. This attempted to open potentially hundreds of documents all at one moment. This caused huge problem, both for the FV servers, and for the user.

Remember, be specific.
Advanced: Returning a Secondary Link
You may find it necessary to have the WM host do some of your clicking for you. This may occur because clicking a button may cause the page to transition to a location you don't want to run a script on. Or it may occur because the end location isn't the best place to return acceptance or failure.

These things happen and have been scripted for in the main WM host. Games such as FrontierVille and CafeWorld use reward pages that require a second click to actually take part in the bonus, but by clicking those buttons or links, the script would then forget the actual acceptance message. The second instance of the script running on the end location would only know that the game loaded and would have to guess as to how it got there.

To prevent that, WM has the ability to accept not only a status code, but a link. That link must include all the parts of the form for which the button to be clicked is part of, and must be represented in the order that the form includes them.

It is up to you to develop code that grabs all that information and properly reports it to the WM, but the WM will actually send that form in for you. The form you send to the WM to process must not also require any more button clicking, as the WM only post the form and cannot be bothered with any of the return information except generic http error responses.

To pass a link like this back to the WM host, simply use the sendMessage function from the WM Library in a different way:

  • sendMessage("status="+statusCode+"&link=["+yourLink+"]");
Your link does not need to be URL encoded for this to work for most apps.
Starter Kit Script
A starter kit code package is available for you to quickly get started.

It includes code that is licensed under Creative Commons. The code therein is created by myself or by other sharing script writers, except where noted.

  • I do not ask to be listed in the copyright section of your userscript.

The starter kit also includes basic instructional comments where useful. See the starter kit for more information.

For answers to all other questions, please refer to the wiki document above before asking below.

Get Starter Kit Script (now updated for use with WM 2)

WM Library
The sidekick starter kit comes equipped with a library of functions to help new sidekick developers get started.

These functions include everything you need to dock with the WM host script, as well as some good tools to make use of simplifying structures presented in the sidekick script.

  • You are NOT required to use the WM Library. But you must send an attachment string to the WM main host that matches the method offered in the library.
For a complete listing of the library's contents, see WM Library Script.

Upgrade Your Sidekick to WM3

An updated tutorial script is now available:

See the change details and instructions for upgrade here.