You should poll at (at least) 60 Hz to ensure you capture new button/axis state at least once per animation frame. Most apps poll in the requestAnimationFrame loop but this isn't always the best solution because you can still miss button presses.
The optimal polling rate is determined by the browser's internal behavior. In Chrome for instance, the browser only fetches new gamepad state every 16 milliseconds (62.5 Hz), so if you poll at ~100 Hz then you will be sure to see every update. It's still possible to miss button presses if they occur between polling iterations, but there's nothing you can do about that. (Almost nothing: Chrome Dev and Canary builds have a chrome://flags#gamepad-polling-rate option you can use to test different internal polling rates.)
The internal polling rate is not defined by the spec, is not directly exposed to the page, and is subject to change. For instance, a browser could choose to coalesce gamepad input updates and align them to the requestAnimationFrame loop which would negate any benefits from polling more frequently. Be cautious when relying on implementation-specific behavior and test your assumptions.
On Firefox you can enable non-standard button and axis events which may let you detect when input updates occur outside your normal polling loop. AFAIK these events are only implemented on FF and are disabled by default, but could be useful for testing.