Inspect When I Work Scheduler

Site wheniwork.comTask inspect-scheduleVersion v3Updated Sep 14, 2026Category browser-automation

Open an authenticated When I Work schedule for a requested date or rolling set of weeks and extract schedule data plus publish state. This skill was captured from a live agent session on wheniwork.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Navigate directly to When I Work scheduler weeks and return structured schedule-grid data, including the schedule publish state. The recipe supports inspecting one week or stitching together consecutive weeks from a caller-supplied start date, including a 12-week collection.

Use Cases

Use when the caller needs to inspect schedule rows, positions, cells, shifts, or whether each schedule week is published. The caller must have an existing authenticated session or provide credentials through the site's normal login flow; this skill does not embed credentials.

Automation Flow

  1. For one requested week, construct https://app.wheniwork.com/scheduler?date={date} where {date} is YYYY-MM-DD. The appx.wheniwork.com host may canonicalize or redirect to the app.wheniwork.com host.
  2. For a rolling collection, step seven days at a time from {start-date}: {start-date}, {start-date + 7 days}, through {start-date + 7 * ({weeks} - 1) days}. Navigate directly to each scheduler URL; do not visit the homepage or use the visible next-week control. The default collection size is one week; callers may request 12 weeks or any other count.
  3. Batch the navigations and page evaluations in the fewest available browser-agent calls. For each URL, use goto(..., {waitUntil: "domcontentloaded"}), then wait until .schedule-row-container or [id^="concern-target-"] exists, allowing several additional seconds for client rendering.
  4. If navigation redirects to https://login.wheniwork.com/?redirect=..., complete the normal authenticated login using the caller's approved session or credentials, then return to the encoded scheduler URL. Do not guess or inject credentials.
  5. On each loaded scheduler page, run this extractor exactly once:
(() => {
const clean = value => (value || '').replace(/\s+/g, ' ').trim();
const text = el => clean(el && el.innerText);
const shiftData = el => ({
  id: el.id || null,
  text: text(el),
  className: typeof el.className === 'string' ? el.className : ''
});
const cellData = cell => ({
  id: cell.id || null,
  text: text(cell),
  shifts: [...cell.querySelectorAll('[id^="shift_"]')].map(shiftData)
});
const cells = [...document.querySelectorAll('[id^="concern-target-"]')].map(cellData);
const rows = [...document.querySelectorAll('.schedule-row-container')].map(row => ({
  text: text(row),
  position: text(row.querySelector('.position-site-details')) || null,
  cells: [...row.querySelectorAll('[id^="concern-target-"]')].map(cellData)
}));
const body = document.body.innerText || '';
const primary = document.querySelector('button[data-testid="schedule-publish-button"]');
const publishContainer = document.querySelector('div.schedule-publish-button');
const publishButton = primary ? {
  text: text(primary),
  ariaLabel: primary.getAttribute('aria-label'),
  className: String(primary.className),
  backgroundColor: getComputedStyle(primary).backgroundColor,
  disabled: primary.disabled === true || primary.getAttribute('aria-disabled') === 'true'
} : null;
const publishText = text(publishContainer || primary);
const everythingPublished = /Everything Published/i.test(body) || /Everything Published/i.test(publishText);
const draftVisible = /Publish\s*&\s*Notify/i.test(body) || /Publish\s*&\s*Notify/i.test(publishText);
const publishState = everythingPublished ? 'published' : (draftVisible ? 'draft' : 'unknown');
const weekMatch = body.match(/[A-Z][a-z]{2}\s+\d{1,2}(?:,\s*\d{4})?\s*[–-]\s*(?:[A-Z][a-z]{2}\s+)?\d{1,2},?\s*\d{4}/);
const loginPage = /login\.wheniwork\.com$/i.test(location.host) ||
  !!document.querySelector('input#email, input[type="email"]');
return {
  url: location.href,
  requestedDate: new URL(location.href).searchParams.get('date'),
  weekLabel: weekMatch ? weekMatch[0] : null,
  authenticated: !loginPage,
  publishState,
  everythingPublished,
  noChanges: /No changes/i.test(body),
  publishButton,
  publishControlsPresent: !!publishContainer,
  publishControlMenuPresent: !!document.querySelector('button[data-testid="schedule-publish-button-controls"]'),
  rowCount: rows.length,
  cellCount: cells.length,
  shiftCount: document.querySelectorAll('[id^="shift_"]').length,
  rows,
  cells
};
})()
  1. For a collection, return one extractor object per requested date in chronological order. Validate that each returned requestedDate and weekLabel correspond to the intended week; do not treat a missing grid or an unauthenticated result as a valid publish state.

Possible Friction Points

  • The non-obvious date filter is the date={YYYY-MM-DD} query parameter; it selects the schedule week containing that date, so {start-date} does not need to fall on the account's week-start day. When I Work lets each account choose its week-start day; the observed run used Saturday, and pinning collection dates to Saturday would land every request mid-week for a Monday-start account. Consecutive weeks can be fetched by adding seven days to the date rather than clicking button.navigate-forward.
  • Direct date URLs on app.wheniwork.com are the shortest reliable path even when the initial application host is appx.wheniwork.com; the app may canonicalize between these hosts.
  • The scheduler is client-rendered. domcontentloaded can precede the grid and publish controls by several seconds, so wait for .schedule-row-container or [id^="concern-target-"] and allow a bounded settling period.
  • Publish controls use div.schedule-publish-button, button[data-testid="schedule-publish-button"], and button[data-testid="schedule-publish-button-controls"]. Visible Everything Published indicates published; Publish & Notify indicates a draft; otherwise report unknown and retain the button metadata.
  • Schedule positions are represented by .position-site-details; day/assignment cells use IDs beginning with concern-target-, and shift elements use IDs beginning with shift_.
  • Unauthenticated navigation can redirect to login.wheniwork.com with the original scheduler URL URL-encoded in redirect. Preserve the intended URL and return to it after approved authentication.
  • The application may switch between appx.wheniwork.com and app.wheniwork.com; treat either authenticated application host as valid.
  • Do not infer entity IDs, company identity, week boundaries, or login state from nearby text. Verify the loaded URL, requested date, week label, and authenticated result.
  • A row containing text such as Need Driver is still a normal schedule row; include it in the returned row data rather than filtering it out.
  • Clicking button.navigate-forward changes the displayed week but is unnecessary for collection runs and may not provide a stable URL for later validation; prefer independently navigated date URLs.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=wheniwork.com&task=inspect-schedule