Napkin programming: on('chat:message', function(msg) { var args = msg.content.split(' '), command = args.shift().toLowerCase().substring(1); if (msg.type !== 'api') return; if (command !== 'setpages') return; if (!playerIsGM(msg.playerid)) return; if (!state.setpages) { state.setpages = {}; } _.each(args, function(arg) { var tuple = arg.toLowerCase().split(':'), player, page; if (tuple.length !== 2) return; player = filterObjs(function(obj) { if (obj.get('type') !== 'player') return false; return obj.get('displayname').toLowerCase().indexOf(tuple[0]) === 0; })[0]; page = filterObjs(function(obj) { if (obj.get('type') !== 'page') return false; return obj.get('name').toLowerCase().indexOf(tuple[1]) === 0; })[0]; if (player && page) { state.setpages[player.id] = page.id; } else if (player && tuple[1] === 'reset') { delete state.setpages[player.id]; } else { sendChat('System', '/w gm Could not find player ' + tuple[0] + ' and/or page ' + tuple[1]); } }); }); on('change:player:_online', function(obj, prev) { var playerspecificpages = Campaign().get('playerspecificpages'); if (!obj.get('online')) return; // Just logged off if (!state.setpages) return; if (state.setpages[obj.id]) { if (!playerspecificpages) { playerspecificpages = {}; } playerspecificpages[obj.id] = state.setpages[obj.id]; } else { if (playerspecificpages && playerspecificpages[obj.id]) { delete playerspecificpages[obj.id]; } if (playerspecificpages && _.keys(playerspecificpages).length === 0) { playerspecificpages = false; } } Campaign().set('playerspecificpages', playerspecificpages); }); So you would set players' pages like !setpages Kerberos:Minty's Brian:Town to set you to the page with the name starting with "Minty's" and me to the page starting with "Town". You could also do it as two separate !setpages calls. To remove the default setting, you would use !setpages Kerberos:reset . The script should then move them to the appropriate page the next time that player loads the VTT. Note: This script is untested.