Browse businesses Browse shifters How it works Pricing For businesses For shifters Help About
Sign in Sign up free

← All posts

Reviews grew up, plus locks on the doors

Reviews can be per-shift now. The reviewee can post a response under any review. Disputes go to a moderation queue. Two-factor authentication is live. Stuck card charges that need a confirmation from your bank are now flagged, emailed, and one-click resolved.

  • feature
  • security
  • payments
  • reviews

Three things shipped today. The first was overdue and the next two are about closing a door that used to be open.

"Built-in clock-in" is built in now

The compare pages have always said ShiftSee has built-in clock-in. Until today, that was a bare timestamp. The shifter tapped a button. The system wrote down the time. That was it. No location check. No photo. Nothing to back up the timestamp if anyone questioned it.

That changes today.

When a shifter clocks in or out, the platform now records:

  • Where they were (lat/lon at the moment of the tap).
  • How far from the worksite they were (Haversine distance to the business's stored address).
  • Whether they overrode a warning (the "I'm here" tap that fires when the GPS says they're outside the radius but they swear they're not).
  • A photo, if the business requires one.

Businesses opt in by setting a geofence radius (off by default, sensible 250m default value when they enable it). They can also flip on "require a photo at clock-in / clock-out." Both controls reach via the existing settings endpoint today; a dedicated slider + toggle on the dashboard ships in the next pass.

For shifters: nothing changes about the clock-in tap. The browser asks for location once, captures it silently, and your shift starts. If your business wants a photo, the camera opens, you take one, you're in. If you're outside the geofence and the business is in hard-fail mode, you get a confirm dialog with an override option in case the GPS is wrong.

Two server modes: soft (default; distance is recorded but not blocking) and hard (SHIFT_CLOCK_GEOFENCE_HARD_FAIL=true; out-of-radius requires an explicit "I'm here" override). Most operators will start with soft and switch to hard once the data tells them where the noise actually is.

Reviews grew up

Reviews used to be one number. One per (business, shifter) pair, in each direction. The thinking was, "rate the relationship, not each shift." It worked when you had a handful of reviews per profile. It stopped working as soon as anyone had a long history with the same business and wanted to rate the most recent shift differently from one nine months ago.

So today reviews can be per-shift. The schema understands "this is a review of the November 14 shift specifically." The old rule (one per pair, total) is preserved for legacy entries; new reviews coming in get pinned to the shift they're about. Multiple reviews per pair are now expected, not blocked.

That's the structural change. Three things sit on top of it.

Respond to a review

If you're the person being reviewed, there's a "Respond" button under each of your reviews. Tap it, write what you want to say, post it. Your response shows up publicly under the review with your name above it.

This matters because, until today, a one-star review was just a one-star review. Now you can say "we'd already issued a refund and offered a different time slot, here's the screenshot" and the next person reading the page sees both sides. Reviews are conversations now, not pronouncements.

Dispute a review

If a review is genuinely wrong (a case of mistaken identity, a fabrication, a violation of the review guidelines), there's a "Dispute" link. Click it, write up why you think it's wrong, file. The review stays publicly visible while it's pending; disputing isn't a silent mute button. An admin from ShiftSee reads your reason, looks at the underlying shift, and decides:

  • Upheld: the review gets hidden from public lists going forward. Stays in our database for audit but stops affecting your average.
  • Rejected: the review stays exactly where it was. The dispute closes.

We err strongly on the side of leaving honest reviews visible. The dispute path is for genuinely wrong reviews, not negative-but-true ones.

See the trend, not just the number

There's a small line chart next to the average rating on every shifter profile. 90 days of weekly buckets. The average doesn't tell you whether the shifter is improving or sliding; the trend does.

This is small visually but it changes how reputations work. A 4.2-star shifter trending up looks different from a 4.2-star shifter trending down, and now you can see which one you're looking at.

A note on what we didn't build

We didn't add the actionable Respond / Dispute buttons to the business detail page in this first cut. They're on shifter profiles only for now. The display additions (response text + dispute pill) are everywhere; the buttons land on business profiles in a follow-up.

We also didn't build an admin queue UI. The endpoints are live (/v1/review/disputes returns pending entries, /v1/review/dispute/resolve decides them); the queue page comes next. For now, ShiftSee admins can use the API directly via the admin console.

Two-factor authentication

Two-factor authentication

Open the avatar dropdown, look for Two-factor authentication, click it. There's a button to turn it on. Tap it.

What happens next:

  1. We show you a QR code. Open your authenticator app (1Password, Authy, Google Authenticator, Bitwarden, Apple Passwords, Microsoft Authenticator, any of them work) and scan it. Or type in the manual key if you can't scan.
  2. Your app starts showing a 6-digit code that changes every 30 seconds. Type it in.
  3. We give you ten one-time-use backup codes. Save them somewhere safe (a password manager, your filesystem's secure notes, anywhere you'd put a recovery key). You only see them once. They're your way back in if you ever lose your phone.

That's it. Next time you sign in, after your password, we'll ask for the rotating code from your app.

If you ever lose your authenticator, use one of the backup codes instead. They work once each. When they're running low, regenerate a fresh set of ten from settings (this invalidates the old ones, so do it before you actually need to).

When you want to turn it off, the same settings page lets you do that, but you have to type in a current code first, so a stolen browser session can't quietly disable it.

"Don't ask me again on this computer"

The 2FA prompt has a checkbox: Trust this device for 30 days. Tick it on a device you own, and the next time you sign in from the same browser, you skip straight past the 2FA prompt. The day-30 mark is a hard limit (cookie expires; you'll get the prompt again).

The settings page shows every browser you've trusted, with "last used" and IP, and a "Sign out" button next to each one. There's also a "Sign out everywhere" button if you want to invalidate all of them at once. Two things automatically wipe the trusted list: turning 2FA off (clean slate), and regenerating your backup codes (the recovery action you'd only take if you thought someone had gotten in).

There's also one more thing happening behind the scenes that's worth knowing about. Every time the cookie successfully skips the 2FA prompt, the underlying token quietly rotates. So if someone copied the cookie off a sleeping laptop, the moment you sign in on that laptop again, their copy stops working. They have to re-steal the cookie to keep using it, and they'll get one shot before you sign in next. It's not bulletproof; it's the same idea as a hotel keycard that gets re-keyed every time you tap it. Most cookie-theft attacks just stop being viable.

Why now

Passwords get reused. Passwords get phished. Passwords get leaked in unrelated breaches and someone tries them on every site they can think of. None of that matters when there's a code rotating on your phone that they don't have.

We've been pre-authenticating new cards with 3DS at save time for a while (so the first off-session charge doesn't get stuck), and we send phone OTP codes for sign-up verification. Two-factor at sign-in is the missing piece. It's also the prerequisite for some compliance work coming up; if you're a business, this becomes a checkbox you're glad you have.

What's not in this version

  • SMS-based 2FA (where the code arrives by text instead of from an app) is sketched but not turned on yet. Telnyx is processing our 10DLC campaign approval; once that's through, you'll see "SMS" as a method choice on the settings page. For now: TOTP via authenticator app.
  • Push-based 2FA (tap an "approve sign-in" button on your phone instead of typing a code) is on a longer-term roadmap. The TOTP flow is what every authenticator app supports, so it works everywhere on day one.

Stuck card charges resolve themselves

This was the other half of today.

If you've ever seen a "scheduled but never charged" looking shift, that's almost always 3DS, the bank's regulation-required confirmation step for off-session charges. Cards from India, the EU, the UK, and increasingly Canada often need it. Until today, when this happened, the platform recorded a stuck PaymentIntent and quietly moved on. You wouldn't know.

Now it does three things:

  • Flags the invoice. No more "looks paid but isn't."
  • Emails you a confirm link. Subject: "Action required: confirm your card payment on ShiftSee."
  • Shows a banner on your dashboard with a one-click confirm button next to each stuck charge.

Click through, tap confirm, your bank's prompt shows up (3DS modal: code, fingerprint, face scan, whatever your bank uses), approve, the charge completes, you're back on the dashboard. About thirty seconds.

If it fails (you cancel, the issuer declines, the code doesn't match), the invoice rolls back to "pending" and you can retry from the dashboard with the same or a different card.

This was technically possible to fix without 2FA shipping (they're independent), but they share a theme. Both are about your account doing the right thing on its own when something needs your attention. Locking the door behind you, in two ways.

Full release notes →