Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Shivamyadav's avatar

Prevent Users From Opening the Same Test in Multiple active Tabs?

I am building an online test/exam system in Laravel where users access URLs like:

http://manual5.uishare.local/test/{id}/attempt

I want to prevent a user from:

Opening the same test in multiple tabs

If a test is already active, I want to show a message like: "This test is already active in another session/tab."

My concerns:

  1. Reliability
  2. Preventing race conditions
  3. Handling browser crashes/tab closes
  4. Supporting scalability
  5. Avoiding false locks
  6. Security against bypassing frontend checks
0 likes
8 replies
Glukinho's avatar

Interesting task. I have some ideas but on deep thought they are far from true reliability. I'd listen for other opinions as well.

General idea is: you can't reliably control what is going on in user's browser. An advanced user can break through your protection.

You can't prevent a user from taking screenshots of a tab, closing it and opening new tab with screenshots opened in image viewer, after all.

Snapey's avatar

Maybe something with reverb/pusher and a presence channel?

Make sure each user gets a unique ID for their instance of a test, issue that same ID if the test already exists (eg, they simply refresh the page). Broadcast that Id on the presence channel, and refuse to start a new instance of the test if the presence channel already contains the test ID.

Shivamyadav's avatar

This a actually a solid way to do this.

As my client do not want to increase the payment cost for the pusher so he denies for this.

Any proper alternative solution for this, could you suggest me.

Updated requirements are:

  1. A user can have only ONE active test session at a time for a given test.
  2. Same Session Continuity (Allowed).
  3. Prevent Multi-Tab / Multi-Device Access.
  4. How to handle for the scenario when the browser session expires and device shutdown or user did not finished the test and returned back etc stuffs.
JussiMannisto's avatar

As my client do not want to increase the payment cost for the pusher so he denies for this.

Reverb is free.

imrandevbd's avatar

Snapey's presence channel idea is solid, but if you want to avoid the overhead of Reverb/websockets, you can handle this reliably using a Redis cache lock combined with a JS heartbeat. I've used this exact pattern in production for high-stakes exam platforms.

Backend Lock: In that controller, store the lock in Redis: Cache::put("test_lock_{$test->id}user{$user->id}", $tab_id, 10);. The 10-second TTL is the magic number here.

Enforcement: On the actual test attempt route (and on subsequent test submissions), check this cache key. If the key exists AND the value doesn't match the current request's tab_id, throw your "already active" error.

Shivamyadav's avatar

Thank you for the suggestion 😊.

I will look at this approach and let you know, if I can get it .

Shivamyadav's avatar

This a actually a solid way to do this.

As my client do not want to increase the payment cost for the pusher so he denies for this.

Any proper alternative solution for this, could you suggest me.

Updated requirements are:

  1. A user can have only ONE active test session at a time for a given test.
  2. Same Session Continuity (Allowed).
  3. Prevent Multi-Tab / Multi-Device Access.
  4. How to handle for the scenario when the browser session expires and device shutdown or user did not finished the test and returned back etc stuffs.
DigitalArtisan's avatar

The most reliable way to enforce tab restrictions is to enable Proctored Exams, use third party software like Safe Exam Browser (SEB).

If your building this from scratch, you have a HUGE undertaking.

I've been in the Learning Management System (LMS) business for 20+ years.

My latest requirement led me to OpenEDX, an open source LMS/CMS, founded by Harvard & MIT and stewarded by Axim Collaborative.

Took me about 4 hours to setup, and am able to create/develop courses in a weeks time.

Please or to participate in this conversation.