<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="https://purl.org/dc/elements/1.1/"
     xmlns:dcterms="http://purl.org/dc/terms/"
     xmlns:media="http://search.yahoo.com/mrss/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:cf="https://www.futureplc.com/rss/content-flags"
>
    <channel>
                    <atom:link href="https://www.tomsguide.com/feeds/tag/bluetooth-speakers" rel="self" type="application/rss+xml" />
                            <title><![CDATA[ Latest from Tom's Guide in Bluetooth-speakers ]]></title>
                <link>https://www.tomsguide.com/audio/speakers/bluetooth-speakers</link>
        <description><![CDATA[ All the latest bluetooth-speakers content from the Tom's Guide team ]]></description>
                                    <lastBuildDate>Thu, 16 Jul 2026 15:35:46 +0000</lastBuildDate>
                            <language>en</language>
                                <item>
                                                            <title><![CDATA[ 11 best Bluetooth speaker deals under $100 at Amazon — save up to 50% on Bose, JBL, Anker and more ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/11-best-bluetooth-speaker-deals-under-usd100-at-amazon-save-up-to-50-percent-on-bose-jbl-anker-and-more</link>
                                                                            <description>
                            <![CDATA[ Amazon is slashing the prices on bluetooth speakers for summer. Here are my favorite deals under $100 from Bose, JBL, Anker and more. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">L8DQQXPbnozs5wUvHp4UtH</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/EVEpowToZkhYE7gEKKFyiF-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 16 Jul 2026 15:35:46 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                                    <dc:creator><![CDATA[ Olivia Halevy ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/YAg7Fmh9dGKbg3hULBMWiU.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Olivia is a Deals Writer at Tom’s Guide. She loves all things lifestyle, shopping and sourcing the best deals from some of the top brands, retailers and websites around. From fashion and beauty to smart home and tech, she has an eye for finding practical, stylish, and reasonably-priced items that help make life simpler (and a little more aesthetically-pleasing).&amp;nbsp;Olivia has over five years of experience writing lifestyle, commerce, and branded content for &lt;a href=&quot;http://patch.com/&quot;&gt;Patch.com&lt;/a&gt;. She&#039;s covered major shopping holidays like Amazon Prime Day, Black Friday and Cyber Monday. In her free time, she enjoys trying out new exercise classes, binge-watching the latest viral TV shows, cooking, spending time with family and taking long walks with her dog, Gus.&amp;nbsp;&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/EVEpowToZkhYE7gEKKFyiF-1280-80.jpg">
                                                            <media:credit><![CDATA[Amazon / edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Amazon deals]]></media:description>                                                            <media:text><![CDATA[Amazon deals]]></media:text>
                                <media:title type="plain"><![CDATA[Amazon deals]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/EVEpowToZkhYE7gEKKFyiF-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Summer is here — and with it comes plenty of beach days and pool parties! If you need a bluetooth speaker that can keep up with all the fun vibes, you've come to the right place. </p><p><a href="https://www.amazon.com/s?k=speakers&i=electronics" target="_blank" rel="nofollow">I've been scouring Amazon for affordable speakers</a> and to my surprise, I found a bunch that are under $100. Even better? They come from top brands like Bose, JBL and Anker. Plus, several hold top spots on Tom's Guide's list of <a href="https://www.tomsguide.com/best-picks/best-waterproof-speakers">best waterproof bluetooth speakers</a> we've tested.</p><p>If you're ready to upgrade your bluetooth speaker without depleting your wallet, keep scrolling to check out my favorite Amazon speaker deals starting at just $22. </p><h3 class="article-body__section" id="section-quick-links"><span>Quick Links </span></h3><ul><li><a href="https://www.amazon.com/s?k=speakers&i=electronics" target="_blank" rel="nofollow"><strong>shop all speaker deals on Amazon</strong></a></li><li><strong>Tribit PocketGo: </strong><a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><strong>was $29 now $22</strong></a></li><li><strong>Anker Soundcore 2: </strong><a href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow"><strong>was $45 now $33</strong></a></li><li><strong>JBL Go 5: </strong><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow"><strong>was $54 now $44</strong></a></li><li><strong>Ultimate Ears WonderBoom 4: </strong><a href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow"><strong>was $99 now $51</strong></a></li><li><strong>Bose SoundLink Micro: </strong><a href="https://www.amazon.com/dp/B0FDLCCFQP?" target="_blank" rel="nofollow"><strong>was $129 now $79</strong></a></li><li><strong>JBL Flip 6: </strong><a href="https://www.amazon.com/dp/B09GJVTRNZ?" target="_blank" rel="nofollow"><strong>was $129 now $83</strong></a></li><li><strong>Soundcore Boom 2: </strong><a href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><strong>was $129 now $90</strong></a></li><li><strong>Bose SoundLink Flex (Gen 2): </strong><a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FGY8BBVP?" target="_blank" rel="nofollow"><strong>was $149 now $99</strong></a></li></ul><h3 class="article-body__section" id="section-best-bluetooth-speaker-deals"><span>Best Bluetooth Speaker Deals</span></h3><div class="product"><a data-dimension112="5943348c-811f-11f1-bd33-37cba0d9ad5b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$22" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="XnqELzjemVWDKqXxoESeBh" name="tribit-pocketgo-bluetooth-shower-speaker-e7119067-af9e-4c09-9feb-6f1f593c89d6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XnqELzjemVWDKqXxoESeBh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review" data-dimension112="5943348c-811f-11f1-bd33-37cba0d9ad5b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$22">Tribit PocketGo</a> will be your new best friend. For less than $30, this Bluetooth speaker packs one heck of a punch in the sound department. On top of that, it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for long hikes in unpredictable weather. And I do mean <em>long</em> hikes because the speaker has a total battery life of 20 hours, making it ideal for a weekend camping trip. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="5943348c-811f-11f1-bd33-37cba0d9ad5b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$22">View Deal</a></p></div><div class="product"><a data-dimension112="594334f0-811f-11f1-a74b-9947fb55ede7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$29" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1480px;"><p class="vanilla-image-block" style="padding-top:101.35%;"><img id="iRvkqAH3YBcTTf4zRa7AdC" name="Tribit-StormBox-Mini-Plus-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/iRvkqAH3YBcTTf4zRa7AdC.jpg" mos="" align="middle" fullscreen="" width="1480" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review" data-dimension112="594334f0-811f-11f1-a74b-9947fb55ede7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$29">Tribit StormBox Mini+</a> boasts powerful bass response and detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing so it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow" data-dimension112="594334f0-811f-11f1-a74b-9947fb55ede7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$29">View Deal</a></p></div><div class="product"><a data-dimension112="5943355e-811f-11f1-8e6f-b5d6c32727f8" data-action="Deal Block" data-label="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension48="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension25="$33" href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:48.00%;"><img id="8BpRx7CmiYxHLqkqkGhn7o" name="anker-soundcore-2-portable-bluetooth-spe-135919d3-382b-433e-a4f8-1715f6ec9dd3.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8BpRx7CmiYxHLqkqkGhn7o.jpg" mos="" align="middle" fullscreen="" width="500" height="240" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's <em>actually</em> outdated. <a class="view-deal button" href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow" data-dimension112="5943355e-811f-11f1-8e6f-b5d6c32727f8" data-action="Deal Block" data-label="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension48="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension25="$33">View Deal</a></p></div><div class="product"><a data-dimension112="594335c2-811f-11f1-86d0-9bb5f4f4297d" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YHNWrEwxj5uzgYGXCTeiJ6" name="Go5-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YHNWrEwxj5uzgYGXCTeiJ6.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review" data-dimension112="594335c2-811f-11f1-86d0-9bb5f4f4297d" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44">JBL Go 5</a> boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow" data-dimension112="594335c2-811f-11f1-86d0-9bb5f4f4297d" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44">View Deal</a></p></div><div class="product"><a data-dimension112="59433626-811f-11f1-a1ea-058e50cfad1a" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$49" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1110px;"><p class="vanilla-image-block" style="padding-top:118.65%;"><img id="dsAxZA3JpSDwfF643VP3eB" name="Micro 3 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/dsAxZA3JpSDwfF643VP3eB.jpg" mos="" align="middle" fullscreen="" width="1110" height="1317" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review" data-dimension112="59433626-811f-11f1-a1ea-058e50cfad1a" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$49">Tribit StormBox Micro 3 </a>offers an IP68 rating, a companion app for EQ customization (although some settings cause compression), and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S/" target="_blank" rel="nofollow" data-dimension112="59433626-811f-11f1-a1ea-058e50cfad1a" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$49">View Deal</a></p></div><div class="product"><a data-dimension112="5943368a-811f-11f1-82aa-759414816d13" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1425px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="D7QYGUpe98kCsZkVddg4oV" name="Ultimate Ears Wonderboom 4.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/D7QYGUpe98kCsZkVddg4oV.jpg" mos="" align="middle" fullscreen="" width="1425" height="1425" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The mighty and portable Wonderboom 4 is a great outdoor speaker that goes louder than it has any right to. In our <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review" data-dimension112="5943368a-811f-11f1-82aa-759414816d13" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51">Ultimate Ears WonderBoom 4 review</a>, our reviewer loved its compact size, very good 16-hour battery life and slick rugged looks. It's IP67 water and dust-resistant as well, so you can really take it anywhere to listen to your tunes.<a class="view-deal button" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow" data-dimension112="5943368a-811f-11f1-82aa-759414816d13" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51">View Deal</a></p></div><div class="product"><a data-dimension112="4a7e6878-8123-11f1-af3e-05e77453d77d" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$59" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1115px;"><p class="vanilla-image-block" style="padding-top:49.42%;"><img id="U4eB79RfdkjMCrjY6xNuFm" name="EarFun-UBoomL-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/U4eB79RfdkjMCrjY6xNuFm.png" mos="" align="middle" fullscreen="" width="1115" height="551" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/speakers/bluetooth-speakers/earfun-uboom-l-review" data-dimension112="4a7e6878-8123-11f1-af3e-05e77453d77d" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$59">EarFun UBoom L</a> offers big sound on a budget. This portable speaker produces powerful bass, clear vocals and well-balanced sound across a range of genres. With a dedicated outdoor mode and an IP67 resistance rating, the speaker can soundtrack pool parties and hikes. It has great battery life, and the customizable EQ via the user-friendly companion app works really well.<a class="view-deal button" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow" data-dimension112="4a7e6878-8123-11f1-af3e-05e77453d77d" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$59">View Deal</a></p></div><div class="product"><a data-dimension112="594336ee-811f-11f1-8cfc-1d3c74cc3851" data-action="Deal Block" data-label="The SoundLink Micro is a compact, portable speaker you can take on the road. The Bluetooth speaker is waterproof (IPX7 certified) and offers up to 6 hours of play time off a single charge. It can also be paired with another SoundLink speaker to create a stereo mode." data-dimension48="The SoundLink Micro is a compact, portable speaker you can take on the road. The Bluetooth speaker is waterproof (IPX7 certified) and offers up to 6 hours of play time off a single charge. It can also be paired with another SoundLink speaker to create a stereo mode." data-dimension25="$79" href="https://www.amazon.com/dp/B0FDLCCFQP?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1105px;"><p class="vanilla-image-block" style="padding-top:103.98%;"><img id="YTZZQubUxh8Cg22rMiKso7" name="Bose soundlink" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YTZZQubUxh8Cg22rMiKso7.jpg" mos="" align="middle" fullscreen="" width="1105" height="1149" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The SoundLink Micro is a compact, portable speaker you can take on the road. The Bluetooth speaker is waterproof (IPX7 certified) and offers up to 6 hours of play time off a single charge. It can also be paired with another SoundLink speaker to create a stereo mode.<a class="view-deal button" href="https://www.amazon.com/dp/B0FDLCCFQP?" target="_blank" rel="nofollow" data-dimension112="594336ee-811f-11f1-8cfc-1d3c74cc3851" data-action="Deal Block" data-label="The SoundLink Micro is a compact, portable speaker you can take on the road. The Bluetooth speaker is waterproof (IPX7 certified) and offers up to 6 hours of play time off a single charge. It can also be paired with another SoundLink speaker to create a stereo mode." data-dimension48="The SoundLink Micro is a compact, portable speaker you can take on the road. The Bluetooth speaker is waterproof (IPX7 certified) and offers up to 6 hours of play time off a single charge. It can also be paired with another SoundLink speaker to create a stereo mode." data-dimension25="$79">View Deal</a></p></div><div class="product"><a data-dimension112="594337c0-811f-11f1-8aeb-03772b602a7f" data-action="Deal Block" data-label="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$83" href="https://www.amazon.com/dp/B09GJVTRNZ?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:120.00%;"><img id="33AJemCSzK8fNYEhkUfBtm" name="JBL Flip 6" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/33AJemCSzK8fNYEhkUfBtm.jpg" mos="" align="middle" fullscreen="" width="1000" height="1200" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening. <a class="view-deal button" href="https://www.amazon.com/dp/B09GJVTRNZ?" target="_blank" rel="nofollow" data-dimension112="594337c0-811f-11f1-8aeb-03772b602a7f" data-action="Deal Block" data-label="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$83">View Deal</a></p></div><div class="product"><a data-dimension112="59433752-811f-11f1-a286-09509732d7c0" data-action="Deal Block" data-label="A speaker of this caliber for just $90 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="A speaker of this caliber for just $90 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$90" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3CvgYRTFMbxneUZcepKkae" name="soundcore boom 2" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3CvgYRTFMbxneUZcepKkae.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>A speaker of this caliber for just $90 is unheard of. The Boom 2 has a massive 80W power, meaning it will go <em>loud</em>. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere. <a class="view-deal button" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow" data-dimension112="59433752-811f-11f1-a286-09509732d7c0" data-action="Deal Block" data-label="A speaker of this caliber for just $90 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="A speaker of this caliber for just $90 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$90">View Deal</a></p></div><div class="product"><a data-dimension112="5943381a-811f-11f1-8333-1faca2219b7a" data-action="Deal Block" data-label="SoundLink Flex gen 2 review" data-dimension48="SoundLink Flex gen 2 review" data-dimension25="$99" href="https://www.amazon.com/Bose-SoundLink-Flex-Bluetooth-Speaker/dp/B0FGY8BBVP/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1063px;"><p class="vanilla-image-block" style="padding-top:73.00%;"><img id="4oVcFP6PokTpSnss5yrCLB" name="Bose Soundlink Flex" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4oVcFP6PokTpSnss5yrCLB.jpg" mos="" align="middle" fullscreen="" width="1063" height="776" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The new Bose SoundLink (2nd gen) is a compact and powerful Bluetooth speaker with a durable design. This 1.2-pound speaker is water and dust proof and delivered great sound quality in our <a href="https://www.tomsguide.com/audio/bose-soundlink-flex-2-review" target="_blank" data-dimension112="5943381a-811f-11f1-8333-1faca2219b7a" data-action="Deal Block" data-label="SoundLink Flex gen 2 review" data-dimension48="SoundLink Flex gen 2 review" data-dimension25="$99">SoundLink Flex gen 2 review</a>. With 12 hours of battery life and $59 off, you have yourself a great deal.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Flex-Bluetooth-Speaker/dp/B0FGY8BBVP/" target="_blank" rel="nofollow" data-dimension112="5943381a-811f-11f1-8333-1faca2219b7a" data-action="Deal Block" data-label="SoundLink Flex gen 2 review" data-dimension48="SoundLink Flex gen 2 review" data-dimension25="$99">View Deal</a></p></div><h3 class="article-body__section" id="section-shop-more-deals"><span>Shop more deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Speakers&brands=Sonos%2CAnker%2CBeats&min_discount_ratio=0.95&offer_type=all&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 0;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 0 16px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }            .tg-df-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;        -webkit-line-clamp: 3;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        -webkit-line-clamp: 3;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 16px;      text-align: center;      width: 100%;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      -webkit-line-clamp: 2;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {      -webkit-line-clamp: 3;    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.45);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #5aaf0b; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #4a9109; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>          \x3C/div>          \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \x3Cdiv class="tg-df-filters">        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>        \x3C/div>      \x3C/div>    \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button, .tg-df-container .tg-df-card-cta { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover, .tg-df-container .tg-df-card-cta:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = params.get('view_mode');            }          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            this.searchInput.value = this.currentQuery;          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'discount_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 if (matches.length > 0) {                    this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                    this.autocompleteDropdown.classList.add('active');                 } else {                    this.autocompleteDropdown.classList.remove('active');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  this.deals = [];                  this.render();                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const rewrittenLink = cardLink.getAttribute('href');                const revenueId = cardLink.getAttribute('data-revenue-id');                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getRowsLimit() {          if (this.rowsSelect && this.rowsSelect.value) return parseInt(this.rowsSelect.value, 10);          let configSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {             configSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {             configSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(configSource);          if (params.has('rows')) return parseInt(params.get('rows'), 10) || 12;          return 12;        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }                async loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = this.getRowsLimit();          } else {             this.displayLimit += this.getRowsLimit();          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let dynamicBrandsCounts = {};                    targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim();                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    url.searchParams.append('rows', this.getRowsLimit().toString());          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = this.getRowsLimit();          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: item.name || item.title || item.model_name || item.product_name || 'Unknown Product',            brand: item.brand || '',            productName: item.model_name || item.product_name || item.name || '',            merchant: item.merchant_name || item.merchant || item.retailer || 'Retailer',            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_desc');          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const rewrittenLink = btn.getAttribute('href');                const revenueId = btn.getAttribute('data-revenue-id');                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)} (${this.airedaleTagCounts[tag] || 0})${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                  `}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_div}` : ''}                      ${_div}                    ${_div}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>${deal.isCheckPrice ? 'Check Price' : 'View Deal'}${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" disable-tracking="true" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               dealsHtml += `                 \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                   \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer; display: flex; align-items: center;">Load More${_button}                 ${_div}               `;            }          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += this.getRowsLimit();                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            setTimeout(() => {               if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');               document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));            }, 50);          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The JBL Xtreme 5 and Marshall Stanmore IV cost the same so which one should you buy? I’ve tested both and here’s what I think ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/should-you-buy-jbl-xtreme-5-marshall-stanmore-iv</link>
                                                                            <description>
                            <![CDATA[ Both the rugged JBL Xtreme 5 and the mains-powered Marshall Stanmore IV cost $399 each, so which one is right for you? Here's the one I'd pick. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">6Byd4bbkJFaR5Rk9tdVpgH</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/PcxoiCDF4i2qc7Y8tnsUd9-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 11 Jul 2026 11:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Smart Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/PcxoiCDF4i2qc7Y8tnsUd9-1280-80.jpg">
                                                            <media:credit><![CDATA[Erin Bashford / Nikita Achanta / Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Xtreme 5 and Marshall Stanmore IV]]></media:description>                                                            <media:text><![CDATA[JBL Xtreme 5 and Marshall Stanmore IV]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Xtreme 5 and Marshall Stanmore IV]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/PcxoiCDF4i2qc7Y8tnsUd9-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I test a lot of audio gear, including speakers. Not just <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">Bluetooth speakers</a>, of course: <a href="https://www.tomsguide.com/us/best-smart-speakers,review-4480.html">smart speakers</a>, home speakers, you name it. Sometimes, when I test a speaker and notice that it costs the same as another speaker, my mind can't help but pit them against one another. I'm a tech reviewer, after all, that's my job! But what happens when one's a Bluetooth speaker and the other is a mains-powered home speaker?</p><p>That's what happened this week when I reviewed the beautiful <a href="https://www.tomsguide.com/audio/smart-speakers/marshall-stanmore-iv-review">Marshall Stanmore IV</a>. It's a mains-powered speaker and the latest addition to the fourth iteration of Homeline, Marshall's series of indoors home speakers. I awarded it 4.5-stars and the coveted Editor's Choice Award in my review. And you know what else received the same score?</p><div class="product"><a data-dimension112="3e30f518-7c4b-11f1-8334-7997390bf633" data-action="Deal Block" data-label="Meaty bass with plenty of low-end impact, crisp treble that never sounds fatiguing, and Dynamic Loudness that ensures music sounds the same regardless of the volume: the Stanmore IV does it all. It’s a versatile speaker with Bluetooth, RCA and AUX inputs, and it’s Auracast-enabled for connecting other Marshall home speakers to it." data-dimension48="Meaty bass with plenty of low-end impact, crisp treble that never sounds fatiguing, and Dynamic Loudness that ensures music sounds the same regardless of the volume: the Stanmore IV does it all. It’s a versatile speaker with Bluetooth, RCA and AUX inputs, and it’s Auracast-enabled for connecting other Marshall home speakers to it." data-dimension25="$399" href="https://www.marshall.com/us/en/product/stanmore-iv" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1172px;"><p class="vanilla-image-block" style="padding-top:90.61%;"><img id="wPgJyuaU6RscHNoZr9h6gA" name="Marshall Stanmore IV deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wPgJyuaU6RscHNoZr9h6gA.png" mos="" align="middle" fullscreen="" width="1172" height="1062" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Meaty bass with plenty of low-end impact, crisp treble that never sounds fatiguing, and Dynamic Loudness that ensures music sounds the same regardless of the volume: the Stanmore IV does it all. It’s a versatile speaker with Bluetooth, RCA and AUX inputs, and it’s Auracast-enabled for connecting other Marshall home speakers to it.<a class="view-deal button" href="https://www.marshall.com/us/en/product/stanmore-iv" target="_blank" rel="nofollow" data-dimension112="3e30f518-7c4b-11f1-8334-7997390bf633" data-action="Deal Block" data-label="Meaty bass with plenty of low-end impact, crisp treble that never sounds fatiguing, and Dynamic Loudness that ensures music sounds the same regardless of the volume: the Stanmore IV does it all. It’s a versatile speaker with Bluetooth, RCA and AUX inputs, and it’s Auracast-enabled for connecting other Marshall home speakers to it." data-dimension48="Meaty bass with plenty of low-end impact, crisp treble that never sounds fatiguing, and Dynamic Loudness that ensures music sounds the same regardless of the volume: the Stanmore IV does it all. It’s a versatile speaker with Bluetooth, RCA and AUX inputs, and it’s Auracast-enabled for connecting other Marshall home speakers to it." data-dimension25="$399">View Deal</a></p></div><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review">JBL Xtreme 5</a>. Though I didn't review it — my colleague Erin did — I've listened to it and I agree with everything she said in her review. The Xtreme 5 costs the same as the Stanmore IV: $399 in the U.S. Of course, the Xtreme 5 is a rugged speaker that can be used outdoors, which is quite the opposite of the Stanmore IV. So, if you had to choose one, which is right for you? I know which is right for <em>me</em>, so let's get into it.</p><h2 id="outdoors-or-at-home-listening">Outdoors or at-home listening?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ihaxNtPXv45ssfqDnniGyC" name="Marshall_Stanmore_IV-3" alt="A black Marshall Stanmore IV home speaker" src="https://cdn.mos.cms.futurecdn.net/ihaxNtPXv45ssfqDnniGyC.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><div  class="fancy-box"><div class="fancy_box-title">What do they sound like?</div><div class="fancy_box_body"><p class="fancy-box__body-text">If you want to find out how the speakers sound, check out Erin's <a data-analytics-id="inline-link" href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review">JBL Xtreme 5 review</a> and my <a data-analytics-id="inline-link" href="https://www.tomsguide.com/audio/smart-speakers/marshall-stanmore-iv-review">Marshall Stanmore IV review</a> for our in-depth thoughts on sound quality.</p></div></div><p>The biggest question to ask yourself when deciding between the JBL Xtreme 5 and the Marshall Stanmore IV is this: "Am I taking it outdoors, or leaving it at home?" If the answer is outdoors, then the Xtreme 5 is the natural choice. </p><p>This speaker is extremely rugged, capable of surviving drops and falls. It's IP68-rated, making it waterproof and the most durable speaker on the market right now.</p><p>In terms of portability, the Xtreme 5 weighs 6.4lbs and features a carry strap, so you can lug it around on your shoulder. And just because it's designed for the outdoors doesn't mean you can't use it indoors either. Bluetooth 6.0 wireless and lossless USB-C wired playback make it the speaker that can do everything, really.</p><div class="product"><a data-dimension112="d81786c2-7c4d-11f1-b172-3773e54672d1" data-action="Deal Block" data-label="Perfect for every kind of party, be that beach, pool, house, or anything in between, the JBL Xtreme 5 is like the Xtreme 4 on steroids. It’s bigger, heavier, louder, and even has a longer battery life. Our favorite part, though, is the sound quality — it makes you yearn for the dancefloor." data-dimension48="Perfect for every kind of party, be that beach, pool, house, or anything in between, the JBL Xtreme 5 is like the Xtreme 4 on steroids. It’s bigger, heavier, louder, and even has a longer battery life. Our favorite part, though, is the sound quality — it makes you yearn for the dancefloor." data-dimension25="$399" href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="tQ9AuHnACGmgriw2w7EMg3" name="jbl xtreme 5 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/tQ9AuHnACGmgriw2w7EMg3.png" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Perfect for every kind of party, be that beach, pool, house, or anything in between, the JBL Xtreme 5 is like the Xtreme 4 on steroids. It’s bigger, heavier, louder, and even has a longer battery life. Our favorite part, though, is the sound quality — it makes you yearn for the dancefloor.<a class="view-deal button" href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9/" target="_blank" rel="nofollow" data-dimension112="d81786c2-7c4d-11f1-b172-3773e54672d1" data-action="Deal Block" data-label="Perfect for every kind of party, be that beach, pool, house, or anything in between, the JBL Xtreme 5 is like the Xtreme 4 on steroids. It’s bigger, heavier, louder, and even has a longer battery life. Our favorite part, though, is the sound quality — it makes you yearn for the dancefloor." data-dimension48="Perfect for every kind of party, be that beach, pool, house, or anything in between, the JBL Xtreme 5 is like the Xtreme 4 on steroids. It’s bigger, heavier, louder, and even has a longer battery life. Our favorite part, though, is the sound quality — it makes you yearn for the dancefloor." data-dimension25="$399">View Deal</a></p></div><p>But I wouldn't be so quick to write off the Stanmore IV either. Sure, you can't really use it away from a plug but if it's pure power and rock 'n' roll sound you're after, this is <em>the </em>speaker to get. The main advantage of a mains-powered speaker is that it delivers consistently high volume, as the mains power drives the internal amplifiers at full capacity, delivering a great dynamic range. Battery-powered Bluetooth speakers, on the other hand, often try to conserve energy so they can't always play at consistently high volumes.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1316px;"><p class="vanilla-image-block" style="padding-top:56.23%;"><img id="Pxa5kX2RrieVaEeUz3iQ4a" name="JBL_extreme_517.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/v2/t:228,l:236,cw:1316,ch:740,q:80/Pxa5kX2RrieVaEeUz3iQ4a.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Xtreme 5 can get loud, but the Stanmore IV can get <em>very </em>loud. I've soundtracked dinners on my balcony with the Stanmore IV. Even when it's been playing indoors, it's been loud enough to hear outside. Dynamic Loudness, which is Marshall-speak for fine-tuned frequencies that sound the same regardless of the volume, plays a key role here too, as you can listen at the highest volume without any noticeable distortion. Marshall's 'Made of Loud' motto makes a lot of sense now. </p><h2 id="there-is-another">There is another...</h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/Ko9LQnFb3AdB8UUG8ruiNG.jpg" alt="A black Marshall Acton IV on a bookshelf" /><figcaption><small role="credit">Nikita Achanta / Tom's Guide</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/6gTtmYbVXuDQbax58Q6bqX.jpg" alt="A JBL Go 5 Bluetooth speaker in blue" /><figcaption><small role="credit">Nikita Achanta / Tom's Guide</small></figcaption></figure></figure><div  class="fancy-box"><div class="fancy_box-title">And what do these sound like?</div><div class="fancy_box_body"><p class="fancy-box__body-text">Likewise, to find out more about the sound quality, read my full <a data-analytics-id="inline-link" href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5 review</a> and <a data-analytics-id="inline-link" href="https://www.tomsguide.com/audio/smart-speakers/marshall-acton-iv-review">Marshall Acton IV review</a>.</p></div></div><p>To quote the great philosopher Yoda, "There is another." The Marshall Stanmore IV isn't the only new kid on the block, or addition to the Marshall Homeline IV, if you will. There's also the <a href="https://www.tomsguide.com/audio/smart-speakers/marshall-acton-iv-review">Marshall Acton IV</a>, which is basically a smaller (and cheaper) version of the Stanmore IV. It looks near-identical and its internal hardware is almost the same too — except that it has a smaller, 4-inch woofer compared to the Stanmore IV's 5-inch woofer.</p><div class="product"><a data-dimension112="1d34a750-7c51-11f1-a56f-3740612f3da8" data-action="Deal Block" data-label="The Marshall Acton IV improves on its predecessor by introducing RCA input for connecting your turntable, and it’s Auracast-enabled to connect with other Homeline IV speakers, like the Stanmore IV. It boasts room-filling sound, and carries Marshall’s trademark retro looks and amp-like controls. The treble is crisp and vibrant while the bass is meaty and powerful." data-dimension48="The Marshall Acton IV improves on its predecessor by introducing RCA input for connecting your turntable, and it’s Auracast-enabled to connect with other Homeline IV speakers, like the Stanmore IV. It boasts room-filling sound, and carries Marshall’s trademark retro looks and amp-like controls. The treble is crisp and vibrant while the bass is meaty and powerful." data-dimension25="$299" href="https://www.marshall.com/us/en/product/acton-iv" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1182px;"><p class="vanilla-image-block" style="padding-top:74.79%;"><img id="VJtxvHPqLn8d2eE9oxqRfh" name="Screenshot 2026-07-10 at 12.16.43" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VJtxvHPqLn8d2eE9oxqRfh.png" mos="" align="middle" fullscreen="" width="1182" height="884" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Marshall Acton IV improves on its predecessor by introducing RCA input for connecting your turntable, and it’s Auracast-enabled to connect with other Homeline IV speakers, like the Stanmore IV. It boasts room-filling sound, and carries Marshall’s trademark retro looks and amp-like controls. The treble is crisp and vibrant while the bass is meaty and powerful.<a class="view-deal button" href="https://www.marshall.com/us/en/product/acton-iv" target="_blank" rel="nofollow" data-dimension112="1d34a750-7c51-11f1-a56f-3740612f3da8" data-action="Deal Block" data-label="The Marshall Acton IV improves on its predecessor by introducing RCA input for connecting your turntable, and it’s Auracast-enabled to connect with other Homeline IV speakers, like the Stanmore IV. It boasts room-filling sound, and carries Marshall’s trademark retro looks and amp-like controls. The treble is crisp and vibrant while the bass is meaty and powerful." data-dimension48="The Marshall Acton IV improves on its predecessor by introducing RCA input for connecting your turntable, and it’s Auracast-enabled to connect with other Homeline IV speakers, like the Stanmore IV. It boasts room-filling sound, and carries Marshall’s trademark retro looks and amp-like controls. The treble is crisp and vibrant while the bass is meaty and powerful." data-dimension25="$299">View Deal</a></p></div><p>In a similar vein, the JBL Xtreme 5 isn't the only speaker that dropped in March 2026. I reviewed the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5</a> when it came out and I absolutely loved it. It quickly became my go-to for taking outdoors, as I loved its pocketable form factor.</p><div class="product"><a data-dimension112="1d34a822-7c51-11f1-85af-5bf03cf6ee3d" data-action="Deal Block" data-label="The JBL Go 5 boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension48="The JBL Go 5 boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension25="$44" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHYJ7BS9/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:82.53%;"><img id="hQdfPTCsudcZKzwvoKBQtU" name="Go-5-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/hQdfPTCsudcZKzwvoKBQtU.jpg" mos="" align="middle" fullscreen="" width="1500" height="1238" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Go 5 boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHYJ7BS9/" target="_blank" rel="nofollow" data-dimension112="1d34a822-7c51-11f1-85af-5bf03cf6ee3d" data-action="Deal Block" data-label="The JBL Go 5 boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension48="The JBL Go 5 boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension25="$44">View Deal</a></p></div><p>Just like the Xtreme 5, the Go 5 is also IP68-rated and drop-proof. If the Xtreme 5 is out of your budget, the Go 5 is a fantastic sub-$60 speaker. And this is a nice segue into why we're all here: the speaker I'd choose...</p><h2 id="we-have-a-winner">We have a winner</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Z8JfRf6tebrGAR5hWHRh5R" name="Marshall_Stanmore_IV" alt="A black Marshall Stanmore IV home speaker" src="https://cdn.mos.cms.futurecdn.net/Z8JfRf6tebrGAR5hWHRh5R.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><p>This is a personal take, but I'm not a fan of carrying around big speakers when I go on a picnic with my partner or friends. Thing is, I'm never going to be blasting my tunes outdoors — <a href="https://www.tomsguide.com/audio/you-can-take-a-portable-bluetooth-speaker-with-you-camping-but-heres-why-its-not-the-best-idea-to-use-it-on-your-hike">I don't like disturbing the local wildlife</a>. All I want is a portable speaker that's loud enough to soundtrack a small gathering without disturbing anyone else.</p><p>The JBL Go 5 does just that — and truth be told, many other small speakers do, too, like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a> (which, since reviewing, I still use today). If push came to shove and you asked me to choose between the JBL Xtreme 5 and the Marshall Stanmore IV, I'm going with the Stanmore IV. I love having a speaker that's plugged in all the time, and playing tunes on it when my partner and I are cooking, or she's making art and I'm playing a video game.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.20%;"><img id="5p8xWyUbUNSFSL4BCdNm8C" name="Marshall_Stanmore_IV-11" alt="A black Marshall Stanmore IV home speaker" src="https://cdn.mos.cms.futurecdn.net/5p8xWyUbUNSFSL4BCdNm8C.jpg" mos="" align="middle" fullscreen="" width="2048" height="1151" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><p>If I <em>had </em>to spend $399 on one speaker, the Stanmore IV would be an easy decision for me. It's got the retro looks, the loud and ridiculously stunning sound, and connectivity in spades, and it feels like the perfect home speaker. The Xtreme 5 is no doubt awesome in its own right, but it's just not for me. My ideal combination is a powerful home speaker and a tiny pocketable speaker — so I'm sticking with the Stanmore IV and the Go 5 for as long as I can.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XjalMO"></div>                            </div>                            <script src="https://kwizly.com/embed/XjalMO.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">The JBL Go 5 is one of the best budget speakers I’ve tested, and it offers stellar sound for just $54</a></li><li><a href="https://www.tomsguide.com/audio/smart-speakers/marshall-stanmore-iv-review">‘Easy on the eyes and ridiculously stunning sound’ — I tested the Marshall Stanmore IV home speaker and it’s coming for Sonos’ crown</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review">JBL Xtreme 5 review: The most rugged, bassiest, and gnarliest Xtreme yet</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Best Buy 4th of July sale: Score up to 33% off these 9 Bluetooth speakers from Sony, Klipsch, JBL, and more ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/best-buy-4th-of-july-sale-score-up-to-33-percent-off-these-9-bluetooth-speakers-from-sony-klipsch-jbl-and-more</link>
                                                                            <description>
                            <![CDATA[ Get the party started with one of these seriously good-sounding Bluetooth speakers – all now with healthy discounts. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">JPMnAfETWjyzJNKAaJBqbD</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/4838biTYLTZN6JA3uoH52E-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 30 Jun 2026 19:17:08 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                                    <dc:creator><![CDATA[ Will Salmon ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/HpRWP7Mh9ErgRGoTvZBbBJ.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Will Salmon is Tom&#039;s Guide&#039;s Collections Editor, curating advice on the best products to spend your money on. Will has been writing about tech and entertainment for almost 20 years, including stints as GamesRadar+&#039;s Streaming Editor, editing comics website Newsarama, and writing for lots and lots of magazines.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/4838biTYLTZN6JA3uoH52E-1280-80.jpg">
                                                            <media:credit><![CDATA[Sony, Anker, Klipsch, JBL / Edited by Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A selection of Bluetooth speakers.]]></media:description>                                                            <media:text><![CDATA[A selection of Bluetooth speakers.]]></media:text>
                                <media:title type="plain"><![CDATA[A selection of Bluetooth speakers.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/4838biTYLTZN6JA3uoH52E-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The deals just keep coming! Yes, Amazon's Prime Day sales may be over, but Best Buy is already running a huge 4th of July sale that's offering lots of great bargains. We covered the <a href="https://www.tomsguide.com/tvs/4th-of-july-tv-deals-save-up-to-usd1-700-on-lg-samsung-and-more-at-best-buy">Best Buy TV sale</a> earlier and now we're rounding up the best Bluetooth speakers, which you can get right now with some pretty deep discounts.</p><p>Bluetooth speakers come in all shapes and sizes and have a variety of price points to match. We've started our selection with some good value Soundcore and Marshall offerings that are ideal for taking to the beach or lounging by the pool. We've then turned our attention to some feature-packed offerings from the likes of JBL before rounding out with some seriously high-end speakers from the likes of Sony and Klipsch. </p><p>For more amazing deals, make sure to check out our guide to the best <a href="https://www.tomsguide.com/sales-events/best-4th-of-july-sales-2026-walmart-home-depot-more">4th of July sales</a>.</p>        <div class="featured_product_block featured_block_hero" data-id="712f8dac-c812-4827-ac4f-3e4e108c1cbc">            <a href="https://www.bestbuy.com/product/soundcore-by-anker-boom-2-ipx7-waterproof-floatable-80w-bluetooth-speaker-with-subwoofer-bassup-2-0-custom-rgb-light-effects-black/JJ858R2J8J" data-model-name="Soundcore by Anker Boom 2 Waterproof Floatable Bluetooth Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/SFBcdMYYSfhFFS4dFidjba.jpg" alt="Soundcore by Anker Boom 2 Waterproof Floatable Bluetooth Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Soundcore</div>                                        <div class="featured__title">Soundcore by Anker Boom 2 Waterproof Floatable Bluetooth Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="72e8b1f0-9065-4207-897c-b2786e91ab90">            <a href="https://www.bestbuy.com/product/marshall-emberton-iii-portable-bluetooth-speaker-with-rugged-waterproof-dust-proof-wireless-design-black-brass/CFCR4HZWQ3" data-model-name="Marshall Emberton III Portable Bluetooth Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/pTDwusmBCM8F6nQVfBS4kj.jpg" alt="Marshall Emberton III Portable Bluetooth Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Marshall</div>                                        <div class="featured__title">Marshall Emberton III Portable Bluetooth Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="da87ce23-2726-405d-817b-0d461f206737">            <a href="https://www.bestbuy.com/product/jbl-charge-6-portable-wireless-speaker-2025-black/J7LXFW3J5H" data-model-name="JBL Charge 6 Portable Wireless Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/fNc3HowqkmrigZci7YeZP9.jpg" alt="JBL Charge 6 Portable Wireless Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>JBL</div>                                        <div class="featured__title">JBL Charge 6 Portable Wireless Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="6394d793-4f9d-4169-b8e9-f4287d157704">            <a href="https://www.bestbuy.com/product/sony-ult-field-7-wireless-speaker-black/J7XSRH5SLS" data-model-name="Sony ULT Field 7 Wireless Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/jcBiuei57zrGSDzAbcJr2S.jpg" alt="Sony ULT Field 7 Wireless Speaker."></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Sony</div>                                        <div class="featured__title">Sony ULT Field 7 Wireless Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="0fd1810e-fa9f-4d2b-b99e-69fd694e6858">            <a href="https://www.bestbuy.com/product/klipsch-miami-music-city-bluetooth-party-speaker-black/JX44FC55Y2" data-model-name="Klipsch Miami Music City Bluetooth Party Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/BzW3r6PT8QwtpdanA5diAW.jpg" alt="Klipsch Miami Music City Bluetooth Party Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Klipsch</div>                                        <div class="featured__title">Klipsch Miami Music City Bluetooth Party Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="37fe2c4e-9a04-4d51-a317-dbe53dc403cc">            <a href="https://www.bestbuy.com/product/jbl-party-box-710-portable-party-speaker-2024-black/J7LXFW26JQ" data-model-name="JBL Party Box 710 Party Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/Z5YFfJTwNSdswvDE4HJVth.jpg" alt="JBL Party Box 710 Party Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>JBL</div>                                        <div class="featured__title">JBL Party Box 710 Party Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="790534ee-31fc-415c-9f5c-cd0a02a81e31">            <a href="https://www.bestbuy.com/product/sony-ult-tower-9-wireless-party-speaker-srsult900-black/J7XSRH5HJF" data-model-name="Sony ULT Tower 9 Party Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/2Jg8KepmdYjZu8bGsVDoJn.jpg" alt="Sony ULT Tower 9 Party Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Sony</div>                                        <div class="featured__title">Sony ULT Tower 9 Party Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="fd814dd7-86e9-4a5f-88c0-ee3097d40a6c">            <a href="https://www.bestbuy.com/product/klipsch-new-york-music-city-bluetooth-party-speaker-black/JX44FC55SQ" data-model-name="Klipsch New York Music City Speaker" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/tdvFuabkWw8cNh4ViovHHT.jpg" alt="Klipsch New York Music City Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Klipsch</div>                                        <div class="featured__title">Klipsch New York Music City Speaker</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="8ca1621c-d3c3-4cfa-9c37-04fa3939224e">            <a href="https://www.bestbuy.com/product/sony-ult-tower-10-party-speaker-with-wireless-microphone-black/J7XSRH5SY2" data-model-name="Sony ULT Tower 10 Party Speaker with Wireless Microphone" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:133.33%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/ccNEpLjSb4ZqGBPTSnBm5c.jpg" alt="Sony ULT Tower 10 Party Speaker with Wireless Microphone"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Sony</div>                                        <div class="featured__title">Sony ULT Tower 10 Party Speaker with Wireless Microphone</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ All my family members want to steal this tiny Bluetooth speaker with huge sound from me, and it's only $47 for Prime Day ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/all-my-family-members-want-to-steal-this-tiny-bluetooth-speaker-with-huge-sound-from-me-and-its-only-usd47-for-prime-day</link>
                                                                            <description>
                            <![CDATA[ The Tribit Stormbox Micro 3 is a tiny powerhouse of a Bluetooth speaker; I can’t believe how good it is for the price. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">fHnPYXPyeNxDgFV9EAjLwN</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ebuyeydkrX8PqiaHG6cTDN-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 26 Jun 2026 12:21:25 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ millie.daviswilliams@futurenet.com (Millie Davis-Williams) ]]></author>                    <dc:creator><![CDATA[ Millie Davis-Williams ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/WU6pa7hKuxs5ScCoqcXYWA.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Millie is a Deals Editor at Tom&#039;s Guide specializing in tech deals content. Based in London, Millie has spent a lifetime stubbornly refusing to pay full price on any possible purchase. She has years of searching for the best discounts on the latest and greatest phones, TVs and gadgets under her belt, and knows how to sort the best deals from the rest. Helping readers save on the products they want is her mission, whether it’s an Apple Watch or a new tablet.&lt;/p&gt;&lt;p&gt;Since working at Tom’s Guide, Millie has covered retail events like Prime Day, Black Friday and Cyber Monday extensively, meaning she knows the products readers are looking for and the best times of year to hit “purchase.”&lt;/p&gt;&lt;p&gt;When she’s not looking for discounts, Millie covers news and writes how-to articles about everything from phones, streaming devices, and headphones to apps and video games.&lt;/p&gt;&lt;p&gt;In her spare time, Millie enjoys reading, gaming on her Nintendo Switch and creating digital art. She’s also a fan of watching Disney movies and collecting plush (the latter having totally taken over her bedroom.)&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/ebuyeydkrX8PqiaHG6cTDN-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit Stormbox Micro 3 Bluetooth speaker in hand]]></media:description>                                                            <media:text><![CDATA[Tribit Stormbox Micro 3 Bluetooth speaker in hand]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit Stormbox Micro 3 Bluetooth speaker in hand]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ebuyeydkrX8PqiaHG6cTDN-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I recently got my hands on the Tribit Stormbox Micro 3. I popped it out of the box, charged it up and switched my music on. Not only did it sound amazing, I’ve been using it for weeks since and still haven’t had to recharge.</p><p>I shouldn’t have been surprised, because Tribit consistently makes some of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>. And since it’s <a href="https://www.tomsguide.com/live/news/last-minute-prime-day-deals-picked-by-editors-2026">Prime Day</a> right now, you can score a saving on it that makes it an even better value.</p><div class="product"><a data-dimension112="140a926f-a639-4594-bf68-d05a6277ce82" data-action="Deal Block" data-label="I love my Tribit Stormbox Micro 3. This palm-sized speaker brings huge sound, with customizable EQ, 24 hours of battery life on a charge and easy-to-use controls. It’s also great for taking outdoors with you thanks to its IP68 waterproof rating and drop protection. Best of all — it’s magnetic, so you can mount it on any magnetic surface and listen hands-free." data-dimension48="I love my Tribit Stormbox Micro 3. This palm-sized speaker brings huge sound, with customizable EQ, 24 hours of battery life on a charge and easy-to-use controls. It’s also great for taking outdoors with you thanks to its IP68 waterproof rating and drop protection. Best of all — it’s magnetic, so you can mount it on any magnetic surface and listen hands-free." data-dimension25="$47" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="LDHzrLzgPGmoS2J4wae5eE" name="tribit-stormbox-micro-3-portable-bluetoo-436aec5e-06de-4963-aa5c-3abc29a65587.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/LDHzrLzgPGmoS2J4wae5eE.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>I love my Tribit Stormbox Micro 3. This palm-sized speaker brings huge sound, with customizable EQ, 24 hours of battery life on a charge and easy-to-use controls. It’s also great for taking outdoors with you thanks to its IP68 waterproof rating and drop protection. Best of all — it’s magnetic, so you can mount it on any magnetic surface and listen hands-free.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow" data-dimension112="140a926f-a639-4594-bf68-d05a6277ce82" data-action="Deal Block" data-label="I love my Tribit Stormbox Micro 3. This palm-sized speaker brings huge sound, with customizable EQ, 24 hours of battery life on a charge and easy-to-use controls. It’s also great for taking outdoors with you thanks to its IP68 waterproof rating and drop protection. Best of all — it’s magnetic, so you can mount it on any magnetic surface and listen hands-free." data-dimension48="I love my Tribit Stormbox Micro 3. This palm-sized speaker brings huge sound, with customizable EQ, 24 hours of battery life on a charge and easy-to-use controls. It’s also great for taking outdoors with you thanks to its IP68 waterproof rating and drop protection. Best of all — it’s magnetic, so you can mount it on any magnetic surface and listen hands-free." data-dimension25="$47">View Deal</a></p></div><p>I know Bluetooth speakers aren’t a new concept, but I’m the kind of person who always uses my phone’s speaker for music. I wasn’t expecting to feel such a real difference from a device that’s not much larger than my phone and costs about twenty times less money.</p><p>When I was testing it out, I was blasting tunes so loud that they could be heard all through my house. And probably down the street, too. It brought a new dimension to the tracks I was listening to and a truly 3D-feeling soundscape. My soundtrack of choice the first time I used it was from Pikmin via the Nintendo Music app, and the naturalistic environmental sounds surrounding my ears from every direction made me feel like I was out experiencing the world right alongside the bite-sized creatures from the video game.</p><p>It’s rated for 24 hours of battery life. I’ve been using it for an hour or so a day for weeks since I got it, and the battery still hasn’t died on me. And reminder — this tiny speaker measures just about the same size as the palm of my hand.</p><h2 id="a-magnetic-design-literally">A magnetic design (literally)</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4363px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="mpYmpr4wAMUdFoxsr362Cg" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3" src="https://cdn.mos.cms.futurecdn.net/mpYmpr4wAMUdFoxsr362Cg.jpg" mos="" align="middle" fullscreen="" width="4363" height="2454" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>One of my favorite features about the Tribit Stormbox Micro 3 is that it’s magnetic. I’m always short on desk space, so I struggle to fit even this tiny speaker amongst my other stuff. But thanks to this speaker, I discovered that my desk has magnetic metal legs. Boom, better music and less clutter on my desktop all in one. It’s also great that I can stick it on my fridge door while I’m cooking in the kitchen. And if you’re outdoorsy, you could also mount it on your bike’s handlebars, or attach it to your backpack using the rubber strap.</p><p>I’m not the only person at Tom’s Guide who loves this speaker. My colleague Ashley Thieme wrote about it in her <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review">Tribit Stormbox Micro 3 review</a> and had a ton of praise for its strong, bassy sound. I’m not too bothered about tweaking EQ for my music (sorry, audiophiles,) but take note that it is possible with this speaker. Use the Tribit app and you can tweak the sound exactly to your preferences.</p><p>The Tribit Stormbox Micro 3 has impressed me so much that I’d recommend it to just about anyone. In fact, multiple members of my family have already said they’re going to steal it off of me. So I guess I’ll either have to keep my speaker under lock and key or pick up a few more of them to hand out in the coming weeks.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ After hundreds of hours of testing, these Prime Day Bluetooth speaker deals from $18 are a no-brainer ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/after-hundreds-of-hours-of-testing-these-prime-day-bluetooth-speaker-deals-from-usd18-are-a-no-brainer</link>
                                                                            <description>
                            <![CDATA[ I test Bluetooth speakers for a living, and after spending hundreds of hours listening, these are the best Prime Day deals to snap up from $18. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">DqHVV3ZAECDmhHdqEAtaRE</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/jpEzptsZhkHFTv7MmvTSLo-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 25 Jun 2026 13:26:25 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Audio]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/jpEzptsZhkHFTv7MmvTSLo-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit StormBox Micro 3 ]]></media:description>                                                            <media:text><![CDATA[Tribit StormBox Micro 3 ]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit StormBox Micro 3 ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/jpEzptsZhkHFTv7MmvTSLo-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As I write this, I'm listening to Noah Kahan's new album with the Tribit StormBox Micro 3. That's because it's quickly become one of my favorite <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">Bluetooth speakers</a> that can cope with anything I throw at it (including the current 100ºF weather here in the U.K). </p><p>It's one of many budget speakers I've come to love after hundreds of hours of testing, and it's reached its lowest price since release for Amazon <a href="https://www.tomsguide.com/live/news/anti-prime-day-2026-best-buy-walmart">Prime Day</a>. But it's not the only one — many of the speakers I use regularly have had their prices slashed too. </p><p>I've compiled a list of all of my favorite budget here, and they're all under $50 — bargain!</p><h3 class="article-body__section" id="section-best-cheap-bluetooth-speaker-deals-quick-links"><span>Best cheap Bluetooth speaker deals: Quick links</span></h3><ul><li><strong>Tribit StormBox Micro 3: </strong><a href="https://www.amazon.com/gp/aw/d/B0GF6PPS4S" target="_blank" rel="nofollow"><strong>was $64 now $47 @ Amazon</strong></a><strong></strong></li><li><strong>Tribit PocketGo: </strong><a href="https://www.amazon.com/gp/aw/d/B0FQJR6RTS" target="_blank" rel="nofollow"><strong>was $29 now $18 @ Amazon</strong></a><strong></strong></li><li><strong>Tozo PE1: </strong><a href="https://www.amazon.com/TOZO-Bluetooth-Adjustable-Carabiner-Waterproof/dp/B0DFH1V13J" target="_blank" rel="nofollow"><strong>was $29 now $18 @ Amazon</strong></a><strong></strong></li><li><strong>Anker Soundcore 2: </strong><a href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow"><strong>was $45 now $31 @ Amazon</strong></a></li></ul><div class="product"><a data-dimension112="4827da90-dde9-4ac8-9b96-989ad6ce3501" data-action="Deal Block" data-label="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent. This is its lowest price since its launch, and it's well worth the money because this thing can get loud without sacrificing the audio quality. It's my go-to for listening to music in the backyard as it can withstand rain, and even holds up well in a ridiculous heatwave, which we're having in the U.K. as I write this." data-dimension48="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent. This is its lowest price since its launch, and it's well worth the money because this thing can get loud without sacrificing the audio quality. It's my go-to for listening to music in the backyard as it can withstand rain, and even holds up well in a ridiculous heatwave, which we're having in the U.K. as I write this." data-dimension25="$47" href="https://www.amazon.com/gp/aw/d/B0GF6PPS4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="NeLkxiMuGjdW9eFv5pBd4o" name="tribit-stormbox-micro-3-portable-bluetoo-6c97391d-b794-4c54-9d8d-827054b2b662.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/NeLkxiMuGjdW9eFv5pBd4o.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent. This is its lowest price since its launch, and it's well worth the money because this thing can get <em>loud</em> without sacrificing the audio quality. It's my go-to for listening to music in the backyard as it can withstand rain, and even holds up well in a ridiculous heatwave, which we're having in the U.K. as I write this. <a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0GF6PPS4S" target="_blank" rel="nofollow" data-dimension112="4827da90-dde9-4ac8-9b96-989ad6ce3501" data-action="Deal Block" data-label="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent. This is its lowest price since its launch, and it's well worth the money because this thing can get loud without sacrificing the audio quality. It's my go-to for listening to music in the backyard as it can withstand rain, and even holds up well in a ridiculous heatwave, which we're having in the U.K. as I write this." data-dimension48="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent. This is its lowest price since its launch, and it's well worth the money because this thing can get loud without sacrificing the audio quality. It's my go-to for listening to music in the backyard as it can withstand rain, and even holds up well in a ridiculous heatwave, which we're having in the U.K. as I write this." data-dimension25="$47">View Deal</a></p></div><div class="product"><a data-dimension112="3c7d07c4-a311-40ba-9c78-9578a19080ca" data-action="Deal Block" data-label="I took the Tribit PocketGo on vacation with me to listen to my favorite tracks poolside, and I didn't need to worry about it getting wet. It has a durability rating of IP68, so it can withstand water submersion. It's ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="I took the Tribit PocketGo on vacation with me to listen to my favorite tracks poolside, and I didn't need to worry about it getting wet. It has a durability rating of IP68, so it can withstand water submersion. It's ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$18" href="https://www.amazon.com/gp/aw/d/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="jLtfEymAcrKojEAGkupD5o" name="tribit-pocketgo-bluetooth-shower-speaker-da78390d-ce5d-47f9-a3e4-85ae321126ba.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/jLtfEymAcrKojEAGkupD5o.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>I took the Tribit PocketGo on vacation with me to listen to my favorite tracks poolside, and I didn't need to worry about it getting wet. It has a durability rating of IP68, so it can withstand water submersion. It's ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes.<a class="view-deal button" href="https://www.amazon.com/gp/aw/d/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="3c7d07c4-a311-40ba-9c78-9578a19080ca" data-action="Deal Block" data-label="I took the Tribit PocketGo on vacation with me to listen to my favorite tracks poolside, and I didn't need to worry about it getting wet. It has a durability rating of IP68, so it can withstand water submersion. It's ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="I took the Tribit PocketGo on vacation with me to listen to my favorite tracks poolside, and I didn't need to worry about it getting wet. It has a durability rating of IP68, so it can withstand water submersion. It's ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$18">View Deal</a></p></div><div class="product"><a data-dimension112="fe39681c-2ded-4409-aba0-aeb8ac60147e" data-action="Deal Block" data-label="The Tozo PE1 is another reliable speaker for any eventuality. It may be ultra-budget, but that is no comment on how well it performs. It's fully waterproof and comes with a built-in carabiner, making it easy to take with you anywhere. You can use the speaker with the Tozo Signature Sound app to get an EQ to best suit the kind of music you want to listen to." data-dimension48="The Tozo PE1 is another reliable speaker for any eventuality. It may be ultra-budget, but that is no comment on how well it performs. It's fully waterproof and comes with a built-in carabiner, making it easy to take with you anywhere. You can use the speaker with the Tozo Signature Sound app to get an EQ to best suit the kind of music you want to listen to." data-dimension25="$18" href="https://www.amazon.com/TOZO-Bluetooth-Adjustable-Carabiner-Waterproof/dp/B0DFH1V13J" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="rs8trfnM96cdRtR2CctU7o" name="tozo-pe1-portable-bluetooth-speakers-wit-e498ff5e-420e-4935-927e-b118db150ff5.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/rs8trfnM96cdRtR2CctU7o.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tozo PE1 is another reliable speaker for any eventuality. It may be ultra-budget, but that is no comment on how well it performs. It's fully waterproof and comes with a built-in carabiner, making it easy to take with you anywhere. You can use the speaker with the Tozo Signature Sound app to get an EQ to best suit the kind of music you want to listen to.<a class="view-deal button" href="https://www.amazon.com/TOZO-Bluetooth-Adjustable-Carabiner-Waterproof/dp/B0DFH1V13J" target="_blank" rel="nofollow" data-dimension112="fe39681c-2ded-4409-aba0-aeb8ac60147e" data-action="Deal Block" data-label="The Tozo PE1 is another reliable speaker for any eventuality. It may be ultra-budget, but that is no comment on how well it performs. It's fully waterproof and comes with a built-in carabiner, making it easy to take with you anywhere. You can use the speaker with the Tozo Signature Sound app to get an EQ to best suit the kind of music you want to listen to." data-dimension48="The Tozo PE1 is another reliable speaker for any eventuality. It may be ultra-budget, but that is no comment on how well it performs. It's fully waterproof and comes with a built-in carabiner, making it easy to take with you anywhere. You can use the speaker with the Tozo Signature Sound app to get an EQ to best suit the kind of music you want to listen to." data-dimension25="$18">View Deal</a></p></div><div class="product"><a data-dimension112="c9296965-f006-4495-91e7-2c8aeb144d80" data-action="Deal Block" data-label="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension48="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension25="$31" href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:48.00%;"><img id="8BpRx7CmiYxHLqkqkGhn7o" name="anker-soundcore-2-portable-bluetooth-spe-135919d3-382b-433e-a4f8-1715f6ec9dd3.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/8BpRx7CmiYxHLqkqkGhn7o.jpg" mos="" align="middle" fullscreen="" width="500" height="240" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's <em>actually</em> outdated. <a class="view-deal button" href="https://www.amazon.com/Anker-Soundcore-Portable-Bluetooth-Waterproof/dp/B0FRRMD96F" target="_blank" rel="nofollow" data-dimension112="c9296965-f006-4495-91e7-2c8aeb144d80" data-action="Deal Block" data-label="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension48="I had the Anker Soundcore 2 for many years (it was originally released in 2017), but it still manages to hold up well today. Though you don't get the same booming bass as the offerings from Tribit above, the 24-hour battery life means it's one I've always been able to rely on. Just because a speaker is a little older doesn't mean it's actually outdated." data-dimension25="$31">View Deal</a></p></div><h3 class="article-body__section" id="section-we-re-tracking-all-the-best-prime-day-audio-deals"><span>We're tracking all the best Prime Day audio deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Audio&min_discount_ratio=0.95&sort=date_desc&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 0;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 0 16px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }            .tg-df-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;        -webkit-line-clamp: 3;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        -webkit-line-clamp: 3;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 16px;      text-align: center;      width: 100%;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      -webkit-line-clamp: 2;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {      -webkit-line-clamp: 3;    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.45);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #5aaf0b; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #4a9109; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>          \x3C/div>          \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \x3Cdiv class="tg-df-filters">        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>        \x3C/div>      \x3C/div>    \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = params.get('view_mode');            }          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            this.searchInput.value = this.currentQuery;          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'discount_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 if (matches.length > 0) {                    this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                    this.autocompleteDropdown.classList.add('active');                 } else {                    this.autocompleteDropdown.classList.remove('active');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  this.deals = [];                  this.render();                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const rewrittenLink = cardLink.getAttribute('href');                const revenueId = cardLink.getAttribute('data-revenue-id');                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }                async loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          } else {             this.displayLimit += (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let dynamicBrandsCounts = {};                    targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim();                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    if (this.rowsSelect && this.rowsSelect.value) {            url.searchParams.append('rows', this.rowsSelect.value);          } else {             url.searchParams.append('rows', '12'); // default          }          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = 12;          if (this.rowsSelect && this.rowsSelect.value) {            rowLimit = parseInt(this.rowsSelect.value, 10) || 12;          }          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: item.name || item.title || item.model_name || item.product_name || 'Unknown Product',            brand: item.brand || '',            productName: item.model_name || item.product_name || item.name || '',            merchant: item.merchant_name || item.merchant || item.retailer || 'Retailer',            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_desc');          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const rewrittenLink = btn.getAttribute('href');                const revenueId = btn.getAttribute('data-revenue-id');                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)} (${this.airedaleTagCounts[tag] || 0})${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                  `}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_div}` : ''}                      ${_div}                    ${_div}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>${deal.isCheckPrice ? 'Check Price' : 'View Deal'}${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" disable-tracking="true" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               dealsHtml += `                 \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                   \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer; display: flex; align-items: center;">Load More${_button}                 ${_div}               `;            }          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12);                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            setTimeout(() => {               if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            if (!this.processArticleFired) {                  this.processArticleFired = true;                  document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));               }            }, 50);          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living and I’ve found the best Prime Day speaker deals from Bose, JBL, Marshall and more, starting from just $27 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/amazon-prime-day-2026-bluetooth-speakers-deals</link>
                                                                            <description>
                            <![CDATA[ Whether you want to soundtrack a party, do karaoke in the shower, or simply listen to music out loud, I've found the best Prime Day deals on Bose, JBL and more. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">JuJkjagRgfDDULXKWPUuKM</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/TwtG5aUn6cyrzZVgnMrPTe-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 23 Jun 2026 18:12:37 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/TwtG5aUn6cyrzZVgnMrPTe-1280-80.jpg">
                                                            <media:credit><![CDATA[Marshall / Bose / JBL / Tribit / Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A selection of Bluetooth speakers]]></media:description>                                                            <media:text><![CDATA[A selection of Bluetooth speakers]]></media:text>
                                <media:title type="plain"><![CDATA[A selection of Bluetooth speakers]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/TwtG5aUn6cyrzZVgnMrPTe-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I don't know about you, but I love listening to music whenever possible. Though I usually use earbuds or headphones to do so, I like jamming to my favorite tunes by listening to them through the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> too, especially if I'm hanging out with my partner. Or soundtracking a party. Or performing karaoke in the shower. Or dancing to Tame Impala while I cook.</p><p>Technology has come leaps and bounds, and today, we're spoilt for choice when it comes to speakers. With so many choices, where do you even start? Luckily for you, I review speakers for a living, and this <a href="https://www.tomsguide.com/live/news/prime-day-2026-handpicked-editor-recommended-deals-live">Amazon Prime Day</a>, I've handpicked my top deals, starting from just $27.</p><p>Yep, the <a href="https://www.amazon.com/Tribit-Bluetooth-StormBox-Playtime-Waterproof/dp/B0DSPJZKPK/" target="_blank" rel="nofollow">Tribit StormBox Mini+ is down to just $27</a>! It's the speaker I use at home, and for its size, it can get very loud. But what about those who don't want a small speaker and want a big, boombox-style one with Earth-shaking bass? You're in luck: the <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3/" target="_blank" rel="nofollow">JBL Xtreme 4 is 34% off right now</a>, and this deal saves you $130.</p><p>Fans of rock 'n' roll may want to consider picking up the <a href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Black/dp/B0BC27MM5Z/" target="_blank" rel="nofollow">Marshall Acton III, available for just $179 this Prime Day</a>, and its drool-worthy looks and tactile amp-like controls are a sight to behold. Or if you want a party speaker that doubles as a guitar amp <em>and </em>karaoke machine, how about the <a href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow">Marshall Bromley 750, which is down to its lowest-ever price of $999 right now</a>?</p><p>And there's a lot more where that came from! Keep reading for the best Prime Day speaker deals you can grab this week.</p><h2 id="meet-your-bluetooth-speakers-deals-expert">Meet your Bluetooth speakers deals expert</h2><h2 class="article-body__section" id="section-quick-links"><span>Quick links</span></h2><ul><li><strong></strong><a href="https://www.amazon.com/primeday" target="_blank" rel="nofollow"><strong>Shop all Amazon Prime Day deals now</strong></a><strong></strong></li><li><strong>JBL Flip 7: </strong><a href="https://www.amazon.com/JBL-Flip-Waterproof-Interchangeable-Accessories/dp/B0DMYQ32SC/" target="_blank" rel="nofollow"><strong>was $149 now $94</strong></a><strong></strong></li><li><strong>JBL Xtreme 4: </strong><a href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3/" target="_blank" rel="nofollow"><strong>was $379 now $249</strong></a><strong></strong></li><li><strong>JBL Charge 6: </strong><a href="https://www.amazon.com/JBL-Charge-Waterproof-Drop-Proof-Built/dp/B0DN2ZCZX6/" target="_blank" rel="nofollow"><strong>was $199 now $159</strong></a><strong></strong></li><li><strong>JBL Go 5: </strong><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow"><strong>was $54 now $44</strong></a><strong></strong></li><li><strong>Bose SoundLink Max: </strong><a href="https://www.amazon.com/Bose-SoundLink-Portable-Waterproof-Bluetooth/dp/B0CVL1K7DX/" target="_blank" rel="nofollow"><strong>was $399 now $279</strong></a><strong></strong></li><li><strong>Bose SoundLink Flex (2nd Gen): </strong><a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0DV5H3S16/" target="_blank" rel="nofollow"><strong>was $139 now $99</strong></a><strong></strong></li><li><strong>Marshall Emberton III: </strong><a href="https://www.amazon.com/Marshall-Emberton-Portable-Bluetooth-Speaker/dp/B0GXH3N61Z/" target="_blank" rel="nofollow"><strong>was $179 now $99</strong></a><strong></strong></li><li><strong>Marshall Acton III: </strong><a href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Black/dp/B0BC27MM5Z/" target="_blank" rel="nofollow"><strong>was $299 now $179</strong></a><strong></strong></li><li><strong>Marshall Stanmore III: </strong><a href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTFCR59/" target="_blank" rel="nofollow"><strong>was $399 now $249</strong></a><strong></strong></li><li><strong>Marshall Bromley 750: </strong><a href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow"><strong>was $1,299 now $999</strong></a><strong></strong></li><li><strong>Tribit StormBox Lava: </strong><a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2/" target="_blank" rel="nofollow"><strong>was $139 now $94</strong></a><strong></strong></li><li><strong>Tribit StormBox Micro 3: </strong><a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S/" target="_blank" rel="nofollow"><strong>was $64 now $47</strong></a><strong></strong></li><li><strong>Tribit StormBox Mini+:</strong><a href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow"><strong> was $34 now $27</strong></a></li><li><strong>EarFun UBoom L: </strong><a href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow"><strong>was $79 now $52</strong></a></li><li><strong>8BitDo Retro Cube 2: </strong><a href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow"><strong>was $55 now $49</strong></a></li></ul><h2 class="article-body__section" id="section-best-prime-day-jbl-deals"><span>Best Prime Day JBL deals</span></h2><div class="product"><a data-dimension112="a001cab0-5f1e-4a1f-8385-3005dec17a9d" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$94" href="https://www.amazon.com/JBL-Flip-Waterproof-Interchangeable-Accessories/dp/B0DMYQ32SC/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6723px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="TSUFRZEoBKMVXB5HoEYo4d" name="JBL Flip 7" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/TSUFRZEoBKMVXB5HoEYo4d.jpg" mos="" align="middle" fullscreen="" width="6723" height="6723" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet" data-dimension112="a001cab0-5f1e-4a1f-8385-3005dec17a9d" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$94">JBL Flip 7</a> is small and powerful yet adamantly refuses to compromise on sound quality, particularly bass. There are very few minor things I’d change — let’s beef up that (admittedly still decent) battery life, enable stereo output on other JBL models, and crowbar in a low-latency mode for streaming and gaming.<a class="view-deal button" href="https://www.amazon.com/JBL-Flip-Waterproof-Interchangeable-Accessories/dp/B0DMYQ32SC/" target="_blank" rel="nofollow" data-dimension112="a001cab0-5f1e-4a1f-8385-3005dec17a9d" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$94">View Deal</a></p></div><div class="product"><a data-dimension112="2b8c4704-662c-44dd-af51-d6466b70ee86" data-action="Deal Block" data-label="JBL Xtreme 4" data-dimension48="JBL Xtreme 4" data-dimension25="$249" href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="L2TjtWjKvMz35uXeyxCSKR" name="JBL Xtreme 4.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/L2TjtWjKvMz35uXeyxCSKR.jpg" mos="" align="middle" fullscreen="" width="679" height="679" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Because it has been succeeded by a 5th-gen speaker, now's a great time to buy the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-4-review" data-dimension112="2b8c4704-662c-44dd-af51-d6466b70ee86" data-action="Deal Block" data-label="JBL Xtreme 4" data-dimension48="JBL Xtreme 4" data-dimension25="$249">JBL Xtreme 4</a> as it has been discounted by $130. It boasts customizable EQ, PartyBoost with AuraCast, and ear-splitting (in a good way) volume. We love its IP67 waterproofing, easy-to-use app, and the fact that it doubles as a power bank.<a class="view-deal button" href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3/" target="_blank" rel="nofollow" data-dimension112="2b8c4704-662c-44dd-af51-d6466b70ee86" data-action="Deal Block" data-label="JBL Xtreme 4" data-dimension48="JBL Xtreme 4" data-dimension25="$249">View Deal</a></p></div><div class="product"><a data-dimension112="3742ae23-0d1b-46f0-9f6f-edc0e572c44c" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YHNWrEwxj5uzgYGXCTeiJ6" name="Go5-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YHNWrEwxj5uzgYGXCTeiJ6.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review" data-dimension112="3742ae23-0d1b-46f0-9f6f-edc0e572c44c" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44">JBL Go 5</a> boasts a wide soundstage packed into a compact, pocketable body. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow" data-dimension112="3742ae23-0d1b-46f0-9f6f-edc0e572c44c" data-action="Deal Block" data-label="JBL Go 5" data-dimension48="JBL Go 5" data-dimension25="$44">View Deal</a></p></div><h2 class="article-body__section" id="section-best-prime-day-bose-deals"><span>Best Prime Day Bose deals</span></h2><div class="product"><a data-dimension112="cf2b00d3-f036-45fa-aa66-5596966fae63" data-action="Deal Block" data-label="SoundLink Max" data-dimension48="SoundLink Max" data-dimension25="$279" href="https://www.amazon.com/Bose-SoundLink-Portable-Waterproof-Bluetooth/dp/B0CVL1K7DX/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:958px;"><p class="vanilla-image-block" style="padding-top:83.72%;"><img id="xFfX4WEKpF3opzDYZMKnhB" name="Bose SoundLink Max.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xFfX4WEKpF3opzDYZMKnhB.jpg" mos="" align="middle" fullscreen="" width="958" height="802" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>A great addition to Bose's Bluetooth speaker lineup, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/bose-soundlink-max" data-dimension112="cf2b00d3-f036-45fa-aa66-5596966fae63" data-action="Deal Block" data-label="SoundLink Max" data-dimension48="SoundLink Max" data-dimension25="$279">SoundLink Max</a> delivers expansive stereo sound, a 20-hour battery life and is one of the most practical portable speakers for life on the move. It boasts a wide soundstage and can get very loud without music sounding distorted.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Portable-Waterproof-Bluetooth/dp/B0CVL1K7DX/" target="_blank" rel="nofollow" data-dimension112="cf2b00d3-f036-45fa-aa66-5596966fae63" data-action="Deal Block" data-label="SoundLink Max" data-dimension48="SoundLink Max" data-dimension25="$279">View Deal</a></p></div><div class="product"><a data-dimension112="307842e7-8741-428a-806a-1b09eb8511a2" data-action="Deal Block" data-label="Bose SoundLink Flex Gen 2" data-dimension48="Bose SoundLink Flex Gen 2" data-dimension25="$99" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0DV5H3S16/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1303px;"><p class="vanilla-image-block" style="padding-top:74.75%;"><img id="hfwnfPdrGwgnEcbUXqjbCP" name="SoundLink Flex Bluetooth Speaker (2nd gen)" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/hfwnfPdrGwgnEcbUXqjbCP.png" mos="" align="middle" fullscreen="" width="1303" height="974" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>It’s slightly more expensive than the competition, but the <a href="https://www.tomsguide.com/audio/bose-soundlink-flex-2-review" data-dimension112="307842e7-8741-428a-806a-1b09eb8511a2" data-action="Deal Block" data-label="Bose SoundLink Flex Gen 2" data-dimension48="Bose SoundLink Flex Gen 2" data-dimension25="$99">Bose SoundLink Flex Gen 2</a> justifies its higher price with great sound quality and app connectivity. I think it looks great, too, and the new color options make for a super fashionable portable speaker.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0DV5H3S16/" target="_blank" rel="nofollow" data-dimension112="307842e7-8741-428a-806a-1b09eb8511a2" data-action="Deal Block" data-label="Bose SoundLink Flex Gen 2" data-dimension48="Bose SoundLink Flex Gen 2" data-dimension25="$99">View Deal</a></p></div><h2 class="article-body__section" id="section-best-prime-day-marshall-deals"><span>Best Prime Day Marshall deals</span></h2><div class="product"><a data-dimension112="cd64f3a0-6682-493c-b30b-cc95d48ffc00" data-action="Deal Block" data-label="Marshall Emberton III" data-dimension48="Marshall Emberton III" data-dimension25="$99" href="https://www.amazon.com/Marshall-Emberton-Portable-Bluetooth-Speaker/dp/B0GXH3N61Z/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1509px;"><p class="vanilla-image-block" style="padding-top:99.34%;"><img id="HTvaeX4MhcAV7Mw3cX4oUM" name="marshall Emberton III.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HTvaeX4MhcAV7Mw3cX4oUM.jpg" mos="" align="middle" fullscreen="" width="1509" height="1499" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/marshal-emberton-iii-review" data-dimension112="cd64f3a0-6682-493c-b30b-cc95d48ffc00" data-action="Deal Block" data-label="Marshall Emberton III" data-dimension48="Marshall Emberton III" data-dimension25="$99">Marshall Emberton III</a> is, in one word, epic. It is one of the brand's smaller speakers, but it packs solid sound into a very tasty-looking design. From the control knob found on loads of Marshall gear to the impactful sound, the Emberton III is a great Bluetooth speaker if you’re looking for something unique and stylish.<a class="view-deal button" href="https://www.amazon.com/Marshall-Emberton-Portable-Bluetooth-Speaker/dp/B0GXH3N61Z/" target="_blank" rel="nofollow" data-dimension112="cd64f3a0-6682-493c-b30b-cc95d48ffc00" data-action="Deal Block" data-label="Marshall Emberton III" data-dimension48="Marshall Emberton III" data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="a5fbf596-9366-4937-a1e8-b62788fe2dd9" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that can actually make your setup feel more modern. The physical controls are tactile and satisfying, making sure it's easy for you to get the sound you want. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton III. The bass is also super responsive, making it a top-tier choice for parties." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that can actually make your setup feel more modern. The physical controls are tactile and satisfying, making sure it's easy for you to get the sound you want. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton III. The bass is also super responsive, making it a top-tier choice for parties." data-dimension25="$179" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Black/dp/B0BC27MM5Z/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:120.00%;"><img id="T2qSjTer2AgBjuQkKpsHm" name="Marshall Acton III" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/T2qSjTer2AgBjuQkKpsHm.jpg" mos="" align="middle" fullscreen="" width="1000" height="1200" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Marshall Acton III is a retro-looking Bluetooth speaker that can actually make your setup feel more modern. The physical controls are tactile and satisfying, making sure it's easy for you to get the sound you want. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton III. The bass is also super responsive, making it a top-tier choice for parties.<a class="view-deal button" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Black/dp/B0BC27MM5Z/" target="_blank" rel="nofollow" data-dimension112="a5fbf596-9366-4937-a1e8-b62788fe2dd9" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that can actually make your setup feel more modern. The physical controls are tactile and satisfying, making sure it's easy for you to get the sound you want. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton III. The bass is also super responsive, making it a top-tier choice for parties." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that can actually make your setup feel more modern. The physical controls are tactile and satisfying, making sure it's easy for you to get the sound you want. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton III. The bass is also super responsive, making it a top-tier choice for parties." data-dimension25="$179">View Deal</a></p></div><div class="product"><a data-dimension112="accafa83-ab63-4dfe-9a8f-8b932991e988" data-action="Deal Block" data-label="The Stanmore III completes Marshall's Homeline III lineup, and it's perfect for small spaces as it measures just 13.78 x 8 x 7.4 inches. It packs Class D amplification rated at 50W for the single mid/woofer, while two 15W amps take care of the tweeters. It sounds incredible, and you should get it just for the rock 'n' roll design, in my opinion." data-dimension48="The Stanmore III completes Marshall's Homeline III lineup, and it's perfect for small spaces as it measures just 13.78 x 8 x 7.4 inches. It packs Class D amplification rated at 50W for the single mid/woofer, while two 15W amps take care of the tweeters. It sounds incredible, and you should get it just for the rock 'n' roll design, in my opinion." data-dimension25="$249" href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTFCR59/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wYnAg4Aq77FqRs4Sxa3xn7" name="marshall stanmore iii" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wYnAg4Aq77FqRs4Sxa3xn7.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Stanmore III completes Marshall's Homeline III lineup, and it's perfect for small spaces as it measures just 13.78 x 8 x 7.4 inches. It packs Class D amplification rated at 50W for the single mid/woofer, while two 15W amps take care of the tweeters. It sounds incredible, and you should get it just for the rock 'n' roll design, in my opinion.<a class="view-deal button" href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTFCR59/" target="_blank" rel="nofollow" data-dimension112="accafa83-ab63-4dfe-9a8f-8b932991e988" data-action="Deal Block" data-label="The Stanmore III completes Marshall's Homeline III lineup, and it's perfect for small spaces as it measures just 13.78 x 8 x 7.4 inches. It packs Class D amplification rated at 50W for the single mid/woofer, while two 15W amps take care of the tweeters. It sounds incredible, and you should get it just for the rock 'n' roll design, in my opinion." data-dimension48="The Stanmore III completes Marshall's Homeline III lineup, and it's perfect for small spaces as it measures just 13.78 x 8 x 7.4 inches. It packs Class D amplification rated at 50W for the single mid/woofer, while two 15W amps take care of the tweeters. It sounds incredible, and you should get it just for the rock 'n' roll design, in my opinion." data-dimension25="$249">View Deal</a></p></div><div class="product"><a data-dimension112="1ecb1636-8192-430e-ac69-55c413def5da" data-action="Deal Block" data-label="Marshall Bromley 750" data-dimension48="Marshall Bromley 750" data-dimension25="$999" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="hC3fb877MKHEkgSJ57m2nm" name="Bromley-750-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/hC3fb877MKHEkgSJ57m2nm.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Thanks to a plethora of wired and wireless connectivity options, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review" data-dimension112="1ecb1636-8192-430e-ac69-55c413def5da" data-action="Deal Block" data-label="Marshall Bromley 750" data-dimension48="Marshall Bromley 750" data-dimension25="$999">Marshall Bromley 750</a> party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear.<a class="view-deal button" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow" data-dimension112="1ecb1636-8192-430e-ac69-55c413def5da" data-action="Deal Block" data-label="Marshall Bromley 750" data-dimension48="Marshall Bromley 750" data-dimension25="$999">View Deal</a></p></div><h2 class="article-body__section" id="section-best-prime-day-tribit-deals"><span>Best Prime Day Tribit deals</span></h2><div class="product"><a data-dimension112="c4f5f2fb-76f4-4803-8eb6-ee6b7125a3e3" data-action="Deal Block" data-label="Tribit StormBox Lava" data-dimension48="Tribit StormBox Lava" data-dimension25="$94" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:83.80%;"><img id="GNykPgtqnDpV9wfnHuMJ9L" name="Tribit StormBox Lava Bluetooth Speaker in black" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/GNykPgtqnDpV9wfnHuMJ9L.jpg" mos="" align="middle" fullscreen="" width="679" height="569" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review" data-dimension112="c4f5f2fb-76f4-4803-8eb6-ee6b7125a3e3" data-action="Deal Block" data-label="Tribit StormBox Lava" data-dimension48="Tribit StormBox Lava" data-dimension25="$94">Tribit StormBox Lava</a> packs a punch but won’t break the bank. The sleek design means it’s easily portable, while water- and dustproofing equip it for any situation. The bass will shake the ground around you, but it still manages to produce a well-rounded sound with crisp treble.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2/" target="_blank" rel="nofollow" data-dimension112="c4f5f2fb-76f4-4803-8eb6-ee6b7125a3e3" data-action="Deal Block" data-label="Tribit StormBox Lava" data-dimension48="Tribit StormBox Lava" data-dimension25="$94">View Deal</a></p></div><div class="product"><a data-dimension112="68b15a7e-50f3-407f-939a-610865db8544" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$47" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1110px;"><p class="vanilla-image-block" style="padding-top:118.65%;"><img id="dsAxZA3JpSDwfF643VP3eB" name="Micro 3 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/dsAxZA3JpSDwfF643VP3eB.jpg" mos="" align="middle" fullscreen="" width="1110" height="1317" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review" data-dimension112="68b15a7e-50f3-407f-939a-610865db8544" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$47">Tribit StormBox Micro 3 </a>offers an IP68 rating, a companion app for EQ customization (although some settings cause compression), and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S/" target="_blank" rel="nofollow" data-dimension112="68b15a7e-50f3-407f-939a-610865db8544" data-action="Deal Block" data-label="Tribit StormBox Micro 3" data-dimension48="Tribit StormBox Micro 3" data-dimension25="$47">View Deal</a></p></div><div class="product"><a data-dimension112="d1e57288-124a-4492-a264-515519343437" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$27" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1480px;"><p class="vanilla-image-block" style="padding-top:101.35%;"><img id="iRvkqAH3YBcTTf4zRa7AdC" name="Tribit-StormBox-Mini-Plus-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/iRvkqAH3YBcTTf4zRa7AdC.jpg" mos="" align="middle" fullscreen="" width="1480" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review" data-dimension112="d1e57288-124a-4492-a264-515519343437" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$27">Tribit StormBox Mini+</a> boasts powerful bass response and detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing so it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow" data-dimension112="d1e57288-124a-4492-a264-515519343437" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$27">View Deal</a></p></div><h2 class="article-body__section" id="section-best-prime-day-miscellaneous-deals"><span>Best Prime Day miscellaneous deals</span></h2><div class="product"><a data-dimension112="130232fe-27d8-4ce2-98e7-3ce3c65377d1" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$52" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1115px;"><p class="vanilla-image-block" style="padding-top:49.42%;"><img id="U4eB79RfdkjMCrjY6xNuFm" name="EarFun-UBoomL-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/U4eB79RfdkjMCrjY6xNuFm.png" mos="" align="middle" fullscreen="" width="1115" height="551" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/speakers/bluetooth-speakers/earfun-uboom-l-review" data-dimension112="130232fe-27d8-4ce2-98e7-3ce3c65377d1" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$52">EarFun UBoom L</a> offers big sound on a budget. This portable speaker produces powerful bass, clear vocals and well-balanced sound across a range of genres. With a dedicated outdoor mode and an IP67 resistance rating, the speaker can soundtrack pool parties and hikes. It has great battery life, and the customizable EQ via the user-friendly companion app works really well.<a class="view-deal button" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow" data-dimension112="130232fe-27d8-4ce2-98e7-3ce3c65377d1" data-action="Deal Block" data-label="EarFun UBoom L" data-dimension48="EarFun UBoom L" data-dimension25="$52">View Deal</a></p></div><div class="product"><a data-dimension112="549ce9e6-839f-4f0e-bda8-e1af2c057c61" data-action="Deal Block" data-label="8BitDo Retro Cube 2" data-dimension48="8BitDo Retro Cube 2" data-dimension25="$49" href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:892px;"><p class="vanilla-image-block" style="padding-top:116.82%;"><img id="r5zUUMfK2PzaubVDbQfHCF" name="8BitDo-RetroCube2-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/r5zUUMfK2PzaubVDbQfHCF.jpg" mos="" align="middle" fullscreen="" width="892" height="1042" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/8bitdo-retro-cube-2-review" data-dimension112="549ce9e6-839f-4f0e-bda8-e1af2c057c61" data-action="Deal Block" data-label="8BitDo Retro Cube 2" data-dimension48="8BitDo Retro Cube 2" data-dimension25="$49">8BitDo Retro Cube 2</a> is the quirkiest speaker around, and that’s down to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine.<a class="view-deal button" href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow" data-dimension112="549ce9e6-839f-4f0e-bda8-e1af2c057c61" data-action="Deal Block" data-label="8BitDo Retro Cube 2" data-dimension48="8BitDo Retro Cube 2" data-dimension25="$49">View Deal</a></p></div><h3 class="article-body__section" id="section-we-re-tracking-all-the-best-prime-day-speaker-deals"><span>We're tracking all the best Prime Day speaker deals</span></h3><div class="vizualizer-embed"><div class="tg-df-widget-host" data-widget-config="?search=Speakers&min_discount_ratio=0.95&widget_title=Top+Deals+Handpicked+by+Our+Editors&widget_subtitle=Discover+the+best+discounts+currently+available%2C+curated+daily+by+the+Tom%27s+Guide+Savings+Squad.&bg_color=transparent" data-vizualizer-embed="true"></div>    <script>    /**     * Tom's Guide Deals Finder - Vanilla JS Encapsulated Engine     */    (function() {      // --- Freyr Analytics Adapter ---      function initAnalytics() {        window.dataLayer = window.dataLayer || [];        window.googletag = window.googletag || {};        window.googletag.cmd = window.googletag.cmd || [];        window.hawk = window.hawk || { analytics: { freyr: [] } };        window.hawk.analytics = window.hawk.analytics || { freyr: [] };        window.hawk.analytics.freyr = window.hawk.analytics.freyr || [];        window.freyr = window.freyr || { cmd: [] };        const scriptSrc = 'https://freyr.futurecdn.net/freyr.js';        const hostname = typeof window !== 'undefined' ? window.location.hostname : '';        const isTestEnv = typeof window.navigator !== 'undefined' && (window.navigator.webdriver || window.navigator.userAgent.includes('Headless'));        const shouldSendRealAnalytics = !isTestEnv && hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.includes('run.app');        if (shouldSendRealAnalytics && !document.querySelector(`script[src="${scriptSrc}"]`)) {          const script = document.createElement('script');          script.src = scriptSrc;          script.async = true;          document.head.appendChild(script);        }      }      function storeEventForDebug(name, data) {        if (!window.hawk || !window.hawk.analytics || !window.hawk.analytics.freyr) return;        window.hawk.analytics.freyr.push({ name, data });        try {          if (typeof window !== 'undefined' && window.localStorage) {            window.localStorage.setItem("hawk", JSON.stringify(window.hawk));          }        } catch (e) {          // Ignore storage issues        }        try {          window.dispatchEvent(new CustomEvent("hawk-analytics-update"));        } catch (e) {}      }      function sendToFreyr(eventName, data) {        if (typeof window === 'undefined') return;        window.freyr = window.freyr || { cmd: [] };        window.freyr.cmd.push(() => {          if (window.freyr && window.freyr.pushAndUpdate) {            window.freyr.pushAndUpdate(eventName, data);          }        });      }      function sendEvent(event, skip = false) {        try {          storeEventForDebug(event.name, event.data);          if (!skip) {            sendToFreyr(event.name, event.data);          }        } catch (e) {          // Ensure tracking errors don't surface to the user        }      }      function getCookie(name) {        try {          const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));          return match ? match[2] : null;        } catch (e) {          return null;        }      }      function normalizeCurrency(symbol) {        const map = {          '£': 'GBP',          '$': 'USD',          'A$': 'AUD',          'CA$': 'CAD',          '€': 'EUR'        };        return map[symbol] || symbol;      }      function trackElementInteraction(props) {        sendEvent({          name: 'elementInteraction',          data: {            element: {              action: props.action || "click",              id: props.id || undefined,              class: props.class || undefined,              name: props.name || undefined,              text: props.text || undefined,              label: props.label || undefined,              container: props.container || undefined,              url: props.url || undefined,              articleId: props.articleId || undefined            }          }        });      }      function generateRevenueId(url, productName, merchantName, modelId) {        const str = `${window.location.href}|${productName}|${merchantName}|${modelId || ''}|${new Date().toDateString()}|tomsguide`;        let hash = 0;        for (let i = 0; i < str.length; i++) {          const char = str.charCodeAt(i);          hash = ((hash << 5) - hash) + char;          hash = hash & hash;        }        let numericStr = Math.abs(hash).toString();        while (numericStr.length < 19) {          numericStr += Math.floor(Math.random() * 10).toString();        }        return numericStr.substring(0, 19);      }      function rewriteAffiliateLink(url, territory, revenueId) {        if (!url) return url;        const t = (territory || 'gb').toLowerCase();        return url.replace(/hawk-custom-tracking/g, `tomsguide-${t}-${revenueId}`);      }      function trackHawkEvent(params) {        const { clickType, widgetId, productCategoryName, product, productsArray, zeroBasedProductIndexOrNull, totalDealsOrProducts, areaClicked, merchant, revenueId, isoCurrencyCode, queryName, widgetTypeName } = params;        const data = {          event: "hawkEvent",          category: "Affiliates",          affiliate: {            action: {              type: clickType,              id: widgetId,              event: clickType === "appeared" ? "viewed" : "Click from",              timestamp: Date.now()            },            component: {              flag: "Editor",              product: productCategoryName || "deals",              category: `Signal Deal Finder ${widgetTypeName || "Carousel"} widget`,              type: clickType === "appeared" ? "review" : "signal product",              label: queryName || (product ? (product.name || "") : ""),              index: zeroBasedProductIndexOrNull === null || zeroBasedProductIndexOrNull === undefined ? -1 : zeroBasedProductIndexOrNull,              linkCount: totalDealsOrProducts || 0,              blockLayout: "",              areaClicked: areaClicked || ""            }          },          products: productsArray || (product && merchant ? [            {              product: {                primary: {                  id: product.id || product.matchId || null,                  name: product.name,                  type: "deal",                  price: product.price,                  previousPrice: product.previousPrice || null,                  currency: isoCurrencyCode || "USD",                  preorder: false,                  labels: [],                  link: product.link,                  originalLink: product.originalLink || null,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: null,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: product.globalId || null,                  inStock: product.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: isoCurrencyCode || "USD"                }              },              merchant: {                id: merchant.id || null,                name: merchant.name,                url: merchant.url || null,                network: merchant.network || null              },              model: {                id: product.modelId || null,                brand: product.brand || null,                name: product.name,                parent: product.parent || null              }            }          ] : []),          reviews: [],          _clear: true,          "gtm.uniqueEventId": Date.now() % 10000        };        sendEvent({ name: 'hawkEvent', data });      }      function trackDealClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card" });      }      function trackViewSimilarClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Product Card View Similar" });      }      function trackPriceComparisonClick(params) {        trackHawkEvent({ ...params, clickType: "retailer", areaClicked: "Signal Price Comparison" });      }      function trackReviewClick(params) {        trackHawkEvent({ ...params, clickType: "review", areaClicked: "Signal Product Card Review Link" });      }      function trackShare(params) {        trackHawkEvent({ ...params, clickType: "share", areaClicked: "Signal Product Card Share" });      }      function trackDealsAppeared(widgetId, deals, revenueId, currency, queryName, widgetTypeName) {         if (!deals || deals.length === 0) return;                  const productsArray = deals.slice(0, 50).map((deal) => {            let voucherPct = null;            let rawPrice = parseFloat(deal.rawPrice) || parseFloat(deal.price) || null;            let rawMsrp = parseFloat(deal.rawMsrp) || parseFloat(deal.msrp) || null;            if (rawMsrp > rawPrice && rawPrice > 0) {              voucherPct = Math.round((1 - (rawPrice / rawMsrp)) * 100);            }            let numId = null;            if (deal.externalProductId && !isNaN(parseInt(deal.externalProductId))) {              numId = parseInt(deal.externalProductId);            } else if (deal.id && !isNaN(parseInt(deal.id))) {              numId = parseInt(deal.id);            } else {              numId = deal.matchId || null;            }            return {              product: {                primary: {                  id: numId,                  name: deal.productName || deal.title || "",                  type: "deal",                  price: rawPrice,                  previousPrice: rawMsrp,                  currency: currency || 'USD',                  preorder: false,                  labels: deal.modelBrand || deal.brand ? [                     { type: "brand", value: deal.modelBrand || deal.brand }                  ] : [],                  link: deal.url,                  originalLink: deal.url,                  revenueId: revenueId || null,                  startTime: null,                  endTime: null,                  voucherCode: null,                  voucherAudience: null,                  voucherPercentageSaving: voucherPct,                  voucherMoneySaving: null,                  voucherType: null,                  offerExclusive: false,                  offerScope: null,                  globalId: deal.productKey || null,                  inStock: deal.inStock !== false,                  contractProvider: null,                  contractMinutes: null,                  contractTexts: null,                  contractData: null,                  contractLength: null,                  contractMonthlyPrice: null,                  contractCurrency: currency || 'USD'                }              },              merchant: {                id: deal.merchantId ? parseInt(deal.merchantId) : null,                name: deal.merchant || "Retailer",                url: deal.merchantUrl || null,                network: deal.merchantNetwork || null              },              model: {                id: deal.modelId ? parseInt(deal.modelId) : null,                brand: deal.modelBrand || deal.brand || null,                name: deal.productName || deal.title || "",                parent: deal.modelParent || null              }            };         });                  trackHawkEvent({             clickType: "appeared",             widgetId: widgetId,             productCategoryName: "deals",             zeroBasedProductIndexOrNull: null,             totalDealsOrProducts: deals.length,             productsArray: productsArray,             queryName: queryName,             widgetTypeName: widgetTypeName         });      }      // 1. Setup Shadow DOM Sandbox      const currentScript = document.currentScript;      let hostContainer = null;      let template = null;            if (currentScript) {        let prev = currentScript.previousElementSibling;        while (prev) {          if (prev.tagName === 'TEMPLATE' && prev.classList.contains('tg-df-widget-template')) {            template = prev;          } else if (prev.tagName === 'DIV' && prev.classList.contains('tg-df-widget-host') && !prev.hasAttribute('data-initialized')) {            hostContainer = prev;            break;          }          prev = prev.previousElementSibling;        }      }            // Fallbacks in case script is deferred      if (!hostContainer) {        const hosts = document.querySelectorAll('.tg-df-widget-host:not([data-initialized])');        if (hosts.length > 0) hostContainer = hosts[0];      }            // Safely embedded template for CMS environments      const rawTemplate = `  \x3Cstyle>    /* --- Shadow DOM Base Reset --- */    *, *::before, *::after {      box-sizing: border-box;    }    img, picture, svg, video {      max-width: 100%;      height: auto;      display: block;    }    /*       1. Scoped CSS for Tom's Guide Deals Widget       All classes are prefixed with \`tg-df-\` to prevent CMS style leakage.    */    .tg-df-container {      container-type: inline-size;      container-name: tg-df;      --tg-df-blue: #1F69FF;      --tg-df-blue-hover: #004d8c;      --tg-df-text: #222222;      --tg-df-text-muted: #555555;      --tg-df-bg: #ffffff;      --tg-df-bg-secondary: #f4f4f4;      --tg-df-border: #e2e8f0;      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;      color: var(--tg-df-text);      background-color: transparent;       width: 100%;      max-width: 1200px;      margin: 0 auto;      padding-bottom: 24px;    }    .tg-df-container *, .tg-df-container *::before, .tg-df-container *::after {      margin: 0;      padding: 0;      box-sizing: border-box;    }    .tg-df-container img {      border: none;      margin: 0;      padding: 0;    }    .tg-df-container a {      text-decoration: none;      color: inherit;    }    /*       2. Search & Filter Bar    */    .tg-df-controls {      display: flex;      flex-direction: column;      align-items: center;      gap: 20px;      margin-bottom: 32px;      width: 100%;    }    .tg-df-top-bar {      display: flex;      width: 100%;      max-width: 760px;      gap: 12px;      align-items: center;    }    .tg-df-search-wrapper {      position: relative;      flex: 1;      width: 100%;      box-shadow: 0 8px 24px rgba(0,0,0,0.06);      border-radius: 40px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      z-index: 100;    }    .tg-df-autocomplete-dropdown {      position: absolute;      top: calc(100% + 4px);      left: 0;      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      max-height: 300px;      overflow-y: auto;      z-index: 200;      display: none;    }    .tg-df-autocomplete-dropdown.active {      display: block;    }    .tg-df-autocomplete-item {      padding: 12px 24px;      cursor: pointer;      font-size: 14px;      color: var(--tg-df-text);      transition: background 0.1s ease;    }    .tg-df-autocomplete-item:hover {      background: var(--tg-df-bg-secondary);    }    .tg-df-search-input {      width: 100%;      padding: 16px 64px 16px 24px;      font-size: 16px;      border: 2px solid transparent;      border-radius: 40px;      outline: none;      transition: border-color 0.2s ease, box-shadow 0.2s ease;      color: var(--tg-df-text);      background: transparent;    }    .tg-df-search-input:focus {      border-color: transparent;      box-shadow: 0 0 0 3px rgba(0, 108, 196, 0.15);    }    .tg-df-search-input::placeholder {      color: #999999;    }        .tg-df-search-btn {      position: absolute;      right: 8px;      top: 50%;      transform: translateY(-50%);      width: 40px;      height: 40px;      border-radius: 50%;      background: #222;      border: none;      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: background 0.2s ease;    }        .tg-df-search-btn:hover {      background: #000;    }    .tg-df-search-icon {      width: 16px;      height: 16px;      fill: #fff;    }    .tg-df-settings-wrapper {      position: relative;    }        .tg-df-settings-btn {      width: 48px;      height: 48px;      border-radius: 50%;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      box-shadow: 0 4px 12px rgba(0,0,0,0.04);      display: flex;      align-items: center;      justify-content: center;      cursor: pointer;      transition: all 0.2s ease;      color: var(--tg-df-text-muted);      flex-shrink: 0;    }    .tg-df-settings-btn:hover {      background: var(--tg-df-bg-secondary);      border-color: #0000ff;      color: var(--tg-df-text);    }    .tg-df-settings-btn svg {      width: 24px;      height: 24px;      fill: currentColor;    }    .tg-df-settings-dropdown {      position: absolute;      top: calc(100% + 8px);      right: 0;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 12px;      box-shadow: 0 8px 32px rgba(0,0,0,0.12);      width: 280px;      padding: 20px;      display: none;      z-index: 100;      flex-direction: column;      gap: 20px;    }    .tg-df-settings-dropdown.active {      display: flex;    }        .tg-df-settings-dropdown-backdrop {      display: none;      position: fixed;      inset: 0;      z-index: 99;    }        .tg-df-settings-dropdown-backdrop.active {      display: block;    }    .tg-df-setting-item {      display: flex;      flex-direction: column;      gap: 10px;    }    .tg-df-setting-label {      font-size: 11px;      font-weight: 700;      color: var(--tg-df-text-muted);      text-transform: uppercase;      letter-spacing: 0.5px;    }        .tg-df-region-select {        padding: 10px 12px;        border-radius: 8px;        border: 1px solid var(--tg-df-border);        font-size: 15px;        outline: none;        background: var(--tg-df-bg-secondary);        color: var(--tg-df-text);        cursor: pointer;        width: 100%;    }    .tg-df-toggle {        position: relative;        display: inline-block;        width: 44px;        height: 24px;        flex-shrink: 0;    }    .tg-df-toggle input {        opacity: 0;        width: 0;        height: 0;    }    .tg-df-slider {        position: absolute;        cursor: pointer;        top: 0; left: 0; right: 0; bottom: 0;        background-color: #ccc;        transition: .2s;        border-radius: 24px;    }    .tg-df-slider:before {        position: absolute;        content: "";        height: 18px;        width: 18px;        left: 3px;        bottom: 3px;        background-color: white;        transition: .2s;        border-radius: 50%;    }    .tg-df-toggle input:checked + .tg-df-slider {        background-color: #1F69FF;    }    .tg-df-toggle input:checked + .tg-df-slider:before {        transform: translateX(20px);    }    .tg-df-dl-row {        flex-direction: row;        align-items: center;        justify-content: space-between;    }    .tg-df-dl-row-text {        font-size: 14px;        font-weight: 600;        color: var(--tg-df-text);    }    .tg-df-dl-row-subtext {        font-size: 12px;        font-weight: 400;        line-height: 1.3;        color: var(--tg-df-text-muted);        margin-top: 4px;        display: block;    }    .tg-df-filters {      display: flex;      gap: 12px;      justify-content: center;      flex-wrap: wrap;    }    .tg-df-sort-wrapper {      position: relative;      display: flex;      align-items: center;    }        .tg-df-sort-icon {      position: absolute;      left: 14px;      width: 14px;      height: 14px;      fill: var(--tg-df-text-muted);      pointer-events: none;    }    .tg-df-sort-select, .tg-df-filter-select {      padding: 10px 36px 10px 38px;      font-size: 14px;      border: 1px solid var(--tg-df-border);      border-radius: 100px;      outline: none;      appearance: none;      background-color: var(--tg-df-bg-secondary);      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12'%3E%3Cpath fill='%23555555' d='M6 8L1 3h10z'/%3E%3C/svg%3E");      background-repeat: no-repeat;      background-position: right 14px center;      color: var(--tg-df-text);      cursor: pointer;      font-weight: 500;      transition: all 0.2s ease;    }        .tg-df-price-input::-webkit-outer-spin-button,    .tg-df-price-input::-webkit-inner-spin-button {      -webkit-appearance: none;      margin: 0;    }    .tg-df-price-input {      -moz-appearance: textfield;    }    .tg-df-sort-select:hover, .tg-df-filter-select:hover {      background-color: #e2e8f0;    }    .tg-df-multiselect-container {      position: relative;    }        .tg-df-multiselect-trigger {      display: block;      background: #fff;      user-select: none;      width: 100%;      overflow: hidden;      white-space: nowrap;      text-overflow: ellipsis;    }        .tg-df-multiselect-dropdown {      display: none;      position: absolute;      top: calc(100% + 4px);      left: 0;      width: 100%;      min-width: 220px;      max-height: 300px;      overflow-y: auto;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);      z-index: 100;      padding: 8px 0;    }    .tg-df-multiselect-dropdown.active {      display: block;    }    .tg-df-ms-option {      padding: 8px 16px;      display: flex;      align-items: center;      gap: 8px;      cursor: pointer;      font-size: 14px;    }    .tg-df-ms-option:hover {      background-color: var(--tg-df-bg-secondary);    }        .tg-df-ms-option input {      cursor: pointer;      accent-color: #1f69ff;    }    .tg-df-sort-select:focus, .tg-df-filter-select:focus {      border-color: #0000ff;      box-shadow: 0 0 0 3px rgba(0, 0, 255, 0.2);      background-color: var(--tg-df-bg);    }    /*       3. Deal Grid Layout    */    .tg-df-grid.tg-df-grid-auto {      padding-top: 24px;    }    .tg-df-grid, .tg-df-grid.layout-grid {      display: grid;      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));      gap: 10px;    }    .tg-df-grid.layout-row {      grid-template-columns: 1fr;      gap: 16px;    }        .tg-df-grid.layout-row .tg-df-card {      flex-direction: row;      align-items: stretch;      height: auto;      box-shadow: none;      border-bottom: 1px solid var(--tg-df-border);    }    .tg-df-grid.layout-row .tg-df-card:hover {      box-shadow: none;    }    .tg-df-grid.layout-row .tg-df-card-image-box {      width: 140px;      min-width: 140px;      aspect-ratio: 3/4;      border-right: none;      padding: 16px 16px 16px 32px;    }    .tg-df-grid.layout-row .tg-df-card-body {      padding: 16px;      justify-content: space-between;    }    .tg-df-grid.layout-row .tg-df-card-title {      font-size: 15px;      margin-bottom: 16px;    }    .tg-df-grid.layout-row .tg-df-card-stars { margin-bottom: 8px; }    .tg-df-grid.layout-row .tg-df-card-footer {      flex-direction: column;      align-items: flex-start;      gap: 0;    }    .tg-df-grid.layout-row .tg-df-card-merchant-pill {      margin-bottom: 4px;    }    .tg-df-grid.layout-row .tg-df-card-price-group {      margin-bottom: 8px;    }    .tg-df-grid.layout-row .tg-df-price-group {      width: auto;    }    .tg-df-grid.layout-row .tg-df-card-cta {      width: 100%;      max-width: 200px;      padding: 10px 24px;      font-size: 13px;      flex-shrink: 0;      text-align: center;      justify-content: center;    }    /*       4. Deal Card Design    */    .tg-df-card {      position: relative;      display: flex;      flex-direction: column;      background-color: #ffffff;      border-radius: 0;      overflow: hidden;      transition: transform 0.2s ease, box-shadow 0.2s ease;      text-decoration: none;      color: inherit;      height: 100%;      box-shadow: 0 0 16px rgba(0, 0, 0, 0.08);      border: 1px solid var(--tg-df-border);    }    .tg-df-card:hover {      box-shadow: 0 0 24px rgba(0, 0, 0, 0.12);    }    .tg-df-card-image-box {      width: 100%;      aspect-ratio: 3/4;      background-color: #f8f8f8;      display: flex;      align-items: center;      justify-content: center;      position: relative;      overflow: hidden;      padding: 32px;      flex: 0 0 auto;    }    .tg-df-card-image {      max-width: 100%;      max-height: 100%;      width: auto;      height: auto;      object-fit: contain;      mix-blend-mode: multiply; /* Helps white background images blend into secondary bg */      transition: transform 0.3s ease;    }    .tg-df-card:hover .tg-df-card-image {      transform: scale(1.05); /* Zoom in on hover */    }    .tg-df-card-discount-badge {      position: absolute;      top: 12px;      left: 12px;      background: #dc2626; /* Red */      color: #ffffff;      padding: 6px 8px;      font-size: 11px;      font-weight: 500;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      z-index: 10;    }        .tg-df-card-merchant-pill {      display: block;      padding: 0;      font-size: 11px;      font-weight: 600;      text-transform: uppercase;      letter-spacing: 0.5px;      border-radius: 0;      color: var(--tg-df-text-muted);      margin-bottom: 8px;      white-space: nowrap;      overflow: hidden;      text-overflow: ellipsis;    }    .tg-df-card-body {      padding: 16px;      display: flex;      flex-direction: column;      flex-grow: 1;      min-width: 0;    }    .tg-df-card-badges {      display: flex;      flex-wrap: wrap;      gap: 6px;      margin-bottom: 8px;    }    .tg-df-tag {      display: inline-flex;      align-items: center;      padding: 4px 6px;      font-size: 11px;      font-weight: 700;      text-transform: uppercase;      border-radius: 4px;      gap: 4px;    }    .tg-df-tag-prime {      background-color: #00A8E1;      color: #fff;    }    .tg-df-tag-coupons {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-coupons:hover {      background-color: #e2e8f0;    }        .tg-df-tag-outline {      background-color: #f1f5f9;      color: #334155;      border: 1px solid #cbd5e1;      cursor: pointer;      transition: background-color 0.2s;    }    .tg-df-tag-outline:hover {      background-color: #e2e8f0;    }        @keyframes tg-df-spin {      0% { transform: rotate(0deg); }      100% { transform: rotate(360deg); }    }    .tg-df-coupon-spinner {      border: 2px solid #e2e8f0;      border-top: 2px solid #3b82f6;      border-radius: 50%;      width: 14px;      height: 14px;      animation: tg-df-spin 1s linear infinite;      margin: 4px 8px;      display: inline-block;    }        /* Vouchers Modal */    .tg-df-modal-backdrop {      position: fixed;      top: 0; left: 0; right: 0; bottom: 0;      background: rgba(0,0,0,0.5);      z-index: 10000;      display: flex;      align-items: center;      justify-content: center;      opacity: 0;      pointer-events: none;      transition: opacity 0.3s;    }    .tg-df-modal-backdrop.active {      opacity: 1;      pointer-events: auto;    }    .tg-df-modal {      background: #fff;      border-radius: 12px;      width: 90%;      max-width: 400px;      max-height: 80vh;      display: flex;      flex-direction: column;      box-shadow: 0 10px 40px rgba(0,0,0,0.2);      transform: translateY(20px);      transition: transform 0.3s;    }    .tg-df-modal-backdrop.active .tg-df-modal {      transform: translateY(0);    }    .tg-df-modal-header {      padding: 16px;      border-bottom: 1px solid #e2e8f0;      display: flex;      align-items: center;      justify-content: space-between;    }    .tg-df-modal-title {      font-size: 16px;      font-weight: 600;      margin: 0;    }    .tg-df-modal-close {      background: none;      border: none;      cursor: pointer;      padding: 4px;      color: #64748b;    }    .tg-df-modal-body {      padding: 16px;      overflow-y: auto;    }    .tg-df-voucher-item {      padding: 12px;      border: 1px dashed #cbd5e1;      border-radius: 8px;      margin-bottom: 10px;      background: #f8fafc;      display: flex;      align-items: center;      gap: 12px;      text-decoration: none;      color: inherit;      transition: background-color 0.2s, border-color 0.2s;    }    .tg-df-voucher-item:hover {      background: #f1f5f9;      border-color: #94a3b8;    }    .tg-df-voucher-item:last-child {      margin-bottom: 0;    }    .tg-df-voucher-logo {      width: 48px;      height: 48px;      object-fit: contain;      border-radius: 4px;      background: #fff;      border: 1px solid #e2e8f0;      flex-shrink: 0;    }    .tg-df-voucher-content {      flex: 1;      min-width: 0;    }    .tg-df-voucher-title {      font-size: 14px;      font-weight: 600;      margin: 0 0 4px 0;      line-height: 1.3;      color: #0f172a;    }    .tg-df-voucher-expiry {      font-size: 12px;      color: #64748b;      display: flex;      align-items: center;      gap: 4px;      margin-top: 6px;    }    .tg-df-voucher-code {      display: inline-flex;      align-items: center;      background: #f1f5f9;      border: 1px dashed #cbd5e1;      padding: 6px 10px;      font-family: monospace;      font-weight: 700;      font-size: 14px;      color: #0f172a;      border-radius: 4px;      margin-top: 8px;      cursor: pointer;      transition: all 0.2s ease;    }    .tg-df-voucher-code:hover {      background: #e2e8f0;      border-color: #94a3b8;    }    .tg-df-voucher-code.copied {      background: #ecfdf5;      border-color: #10b981;      color: #10b981;    }    .tg-df-voucher-cta {      display: inline-block;      margin-top: 8px;      font-size: 13px;      font-weight: 600;      color: #2563eb;      text-decoration: none;    }    .tg-df-card-title {      font-size: 15px;      font-weight: 400;      line-height: 1.4;      margin: 0 0 12px 0;      color: var(--tg-df-text);      display: -webkit-box;      -webkit-line-clamp: 2;      -webkit-box-orient: vertical;      overflow: hidden;    }    .tg-df-card-footer {      margin-top: auto;      display: flex;      flex-direction: column;      width: 100%;    }    .tg-df-card-price-group {      display: flex;      flex-direction: row;      align-items: center;      gap: 8px;      margin-bottom: 12px;    }    .tg-df-card-price {      font-size: 16px;      font-weight: 700;      color: #dc2626; /* Red price */      line-height: 1;    }        .tg-df-card-msrp {      font-size: 13px;      color: var(--tg-df-text-muted);      text-decoration: line-through;    }    .tg-df-container .tg-df-card-cta {      display: flex;      align-items: center;      justify-content: center;      width: 100%;      box-sizing: border-box;      background-color: #1f69ff;      color: #ffffff;      font-size: 12px;      font-weight: 700;      text-transform: uppercase;      letter-spacing: 0.5px;      padding: 12px 16px;      border-radius: 0;      border: none;      cursor: pointer;      transition: background-color 0.2s ease;    }    .tg-df-card:hover .tg-df-card-cta,    .tg-df-card-cta:hover {      background-color: #1555cc;    }    .tg-df-container .tg-df-card-cta.tg-df-cta-savings-squad {      background-color: #3c8d0d;    }    .tg-df-card:hover .tg-df-card-cta.tg-df-cta-savings-squad,    .tg-df-card-cta.tg-df-cta-savings-squad:hover {      background-color: #2b6509;    }    /*       5. State & Skeleton Styles    */    .tg-df-message {      grid-column: 1 / -1;      text-align: center;      padding: 48px 24px;      color: var(--tg-df-text-muted);      font-size: 16px;      background: var(--tg-df-bg);      border: 1px solid var(--tg-df-border);      border-radius: 8px;    }    @keyframes tg-df-shimmer {      0% { background-position: -200% 0; }      100% { background-position: 200% 0; }    }    .tg-df-skeleton {      background: linear-gradient(90deg, var(--tg-df-bg-secondary) 25%, #e2e8f0 50%, var(--tg-df-bg-secondary) 75%);      background-size: 200% 100%;      animation: tg-df-shimmer 1.5s infinite;      border-radius: 4px;    }    .tg-df-skeleton-img {      width: 100%;      height: 100%;      position: absolute;      top: 0; left: 0;    }        .tg-df-skeleton-text {      height: 16px;      margin-bottom: 8px;      width: 100%;    }    .tg-df-skeleton-text.short { width: 40%; }    .tg-df-skeleton-text.title { height: 20px; margin-bottom: 16px; }    /* Editor Floating Bar & Elements */    .tg-df-editor-bar {      position: sticky;      top: 0;      z-index: 1000;      background: #111827;      color: #fff;      padding: 12px 16px;      border-radius: 8px;      margin-bottom: 16px;      display: flex;      align-items: center;      justify-content: space-between;      box-shadow: 0 4px 12px rgba(0,0,0,0.15);    }    .tg-df-editor-bar-text {      font-weight: 600;      font-size: 14px;    }    .tg-df-editor-copy-btn {      background: #10b981;      color: #fff;      padding: 6px 16px;      border: none;      border-radius: 4px;      font-weight: 600;      cursor: pointer;      display: flex;      align-items: center;      font-size: 13px;    }    .tg-df-editor-copy-btn:hover { background: #059669; }        .tg-df-deal-checkbox {      position: absolute;      top: 12px;      right: 12px;      z-index: 10;      width: 20px;      height: 20px;      cursor: pointer;      pointer-events: auto;    }    /*       6. Mobile List View (Stacks into a cleaner horizontal row/list)    */    @container tg-df (max-width: 599px) {      .tg-df-controls {        padding: 0 16px;      }            .tg-df-top-bar {        width: 100%;      }            .tg-df-settings-dropdown {        position: fixed;        top: auto;        bottom: 0;        left: 0;        right: 0;        width: 100%;        border-radius: 20px 20px 0 0;        padding: 24px;        box-shadow: 0 -8px 32px rgba(0,0,0,0.15);        z-index: 1000;        border: none;        border-top: 1px solid var(--tg-df-border);      }            .tg-df-settings-dropdown-backdrop.active {        background: rgba(0,0,0,0.4);      }            .tg-df-search-wrapper {        box-shadow: 0 0 16px rgba(0,0,0,0.08);      }            .tg-df-filters {        width: calc(100% + 32px);        margin: 0 -16px;        padding: 0 16px 4px 16px;        display: flex;        justify-content: flex-start;        gap: 8px;        flex-wrap: nowrap;        overflow-x: auto;        -webkit-overflow-scrolling: touch;        scrollbar-width: none;      }      .tg-df-filters::after {        content: "";        display: block;        flex: 0 0 8px;      }      .tg-df-filters::-webkit-scrollbar {        display: none;      }            .tg-df-sort-wrapper {        flex: 0 0 max(42%, 130px);        min-width: 0;      }      .tg-df-sort-wrapper.tg-df-price-range-wrapper {        flex: 0 0 auto;        min-width: max-content;      }            .tg-df-sort-select, .tg-df-filter-select {        width: 100%;        text-align: left;        padding: 10px 24px 10px 32px;        background-position: right 8px center;        text-overflow: ellipsis;        white-space: nowrap;        overflow: hidden;      }      .tg-df-sort-icon {        left: 10px;      }      .tg-df-grid:not(.layout-grid):not(.layout-row),      .tg-df-grid.layout-row {        grid-template-columns: 1fr;        gap: 16px;      }            .tg-df-grid.tg-df-grid-auto {        padding-top: 24px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card,      .tg-df-grid.layout-row .tg-df-card {        flex-direction: row;        align-items: stretch;        height: auto;        box-shadow: none; /* simple line on mobile if preferred, or keep */        border-bottom: 1px solid var(--tg-df-border);      }      .tg-df-grid.tg-df-grid-auto .tg-df-card:hover,      .tg-df-grid.layout-row .tg-df-card:hover {        box-shadow: none;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-image-box,      .tg-df-grid.layout-row .tg-df-card-image-box {        width: 120px;        min-width: 120px;        aspect-ratio: 3/4;        border-right: none;        padding: 12px;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-body,      .tg-df-grid.layout-row .tg-df-card-body {        padding: 12px;        justify-content: space-between;      }      .tg-df-grid.tg-df-grid-auto .tg-df-card-title,      .tg-df-grid.layout-row .tg-df-card-title {        font-size: 14px;        margin-bottom: 12px;        -webkit-line-clamp: 3;      }      /* Single column mobile grid override */      .tg-df-grid.layout-grid {        grid-template-columns: 1fr;        gap: 16px;      }      .tg-df-grid.layout-grid .tg-df-card-image-box {        padding: 12px;      }      .tg-df-grid.layout-grid .tg-df-card-body {        padding: 10px;      }      .tg-df-grid.layout-grid .tg-df-card-title {        font-size: 13px;        -webkit-line-clamp: 3;        margin-bottom: 8px;      }      .tg-df-grid.layout-grid .tg-df-card-price {        font-size: 14px;      }            .tg-df-card-footer {        flex-direction: column;        align-items: stretch;        gap: 0;        width: 100%;        min-width: 0;      }      .tg-df-card-merchant-pill {        margin-bottom: 4px;      }      .tg-df-card-price-group {        flex: 1 1 auto;        margin-bottom: 8px;      }      .tg-df-card-price {        font-size: 16px;      }      .tg-df-card-msrp {        display: block;       }      .tg-df-grid.layout-row .tg-df-card-cta,      .tg-df-container .tg-df-card-cta {        width: 100%;        max-width: none;        min-width: 0;        box-sizing: border-box;        padding: 8px 16px;        font-size: 12px;        flex: 0 0 auto;        text-align: center;        white-space: normal;        line-height: 1.2;      }    }    .tg-df-container.is-carousel {      min-height: 760px;      background-color: #E7F0FF;      padding: 0 0 24px 0;      border-radius: 24px;    }    .tg-df-container.is-carousel.hide-header-details {      min-height: 480px;    }    /*       7. Carousel View Mode    */    .tg-df-container .tg-df-carousel-host {      /* Layout is now handled by container wrapper */    }    .tg-df-container .tg-df-carousel-eyebrow {      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      padding: 24px 16px 0 16px;      display: none;    }    .tg-df-container .tg-df-carousel-query-title {      color: #011535;      font-size: 28px;      font-weight: 600;      padding: 0 16px 24px 16px;      line-height: 1.2;      display: none;    }    .tg-df-container .tg-df-carousel-blue-box {      background-color: transparent;      border-radius: 0;      padding: 24px 24px 0 24px;      margin: 0;      color: #1F69FF;          position: relative;      overflow: hidden;    }    .tg-df-container .tg-df-carousel-bg-circle-1 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-2 {      display: none;    }    .tg-df-container .tg-df-carousel-bg-circle-3 {      display: none;    }    .tg-df-container .tg-df-carousel-box-content {      position: relative;      z-index: 10;    }    .tg-df-container .tg-df-carousel-box-eyebrow {      background-color: transparent;      color: #1F69FF;      font-weight: 700;      font-size: 14px;      text-transform: uppercase;      letter-spacing: 1px;      display: inline-block;      padding: 0;      border-radius: 0;    }    .tg-df-container .tg-df-carousel-box-title {      font-size: 28px;      font-weight: 600;      line-height: 1.2;      margin-top: 8px;      color: #1e293b;    }    .tg-df-container .tg-df-countdown-wrapper {      position: absolute;      top: 0;      right: 0;      display: flex;      flex-direction: column;      align-items: flex-end;      gap: 12px;      transform: scale(0.67);      transform-origin: top right;    }    .tg-df-container .tg-df-countdown-title {      font-size: 16px;      text-align: center;      width: 100%;      font-weight: 600;      color: #011535;      margin: 0;    }    .tg-df-container .tg-df-countdown-blocks {      display: flex;      gap: 16px;    }    .tg-df-container .tg-df-countdown-item {      display: flex;      flex-direction: column;      align-items: center;      gap: 4px;    }    .tg-df-container .tg-df-countdown-box {      width: 59px;      height: 59px;      background: #03FE9E;      border-radius: 15px;      display: flex;      align-items: center;      justify-content: center;    }    .tg-df-container .tg-df-countdown-num {      font-family: 'Inter', sans-serif;      font-weight: 700;      font-size: 20px;      line-height: normal;      color: #011535;    }    .tg-df-container .tg-df-countdown-label {      font-family: 'Inter', sans-serif;      font-weight: 500;      font-size: 16px;      line-height: normal;      color: #1e293b;      text-transform: uppercase;    }    .tg-df-container .tg-df-carousel-box-subtitle {      font-size: 16px;      margin-top: 8px;      font-weight: 300;      color: #1e293b;      line-height: 24px;    }    .tg-df-container .tg-df-carousel-roundels-wrapper {      position: relative;      margin-top: 24px;      margin-left: -24px;      margin-right: -24px;    }    .tg-df-container .tg-df-carousel-roundels {      display: flex;      gap: 16px;      overflow-x: auto;            scrollbar-width: none;      padding-top: 12px;      padding-bottom: 24px;      padding-left: 24px;      padding-right: 24px;      margin-left: 0;      margin-right: 0;    }        .tg-df-container .tg-df-carousel-scroll-left,    .tg-df-container .tg-df-carousel-scroll-right {      position: absolute;      top: 50%;      transform: translateY(-50%);      height: 36px;      width: 36px;      display: flex;      align-items: center;      justify-content: center;      border-radius: 50%;      background-color: #ffffff;      border: 1px solid #e2e8f0;      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);      color: #1F69FF;      cursor: pointer;      transition: all 0.2s;      margin-top: -4px;      z-index: 20;    }    .tg-df-container .tg-df-carousel-scroll-left { left: 8px; }    .tg-df-container .tg-df-carousel-scroll-right { right: 8px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left { left: 0px; }    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right { right: 0px; }    .tg-df-carousel-filters-outer { margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; }    @container tg-df (max-width: 599px) { .tg-df-carousel-filters-outer { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; } }        .tg-df-container .tg-df-carousel-scroll-left:hover,    .tg-df-container .tg-df-carousel-scroll-right:hover {      background-color: #f8fafc;      border-color: #cbd5e1;    }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-left,    .tg-df-carousel-filters-outer .tg-df-carousel-scroll-right {      background-color: rgba(255, 255, 255, 0.4);      border: none;      box-shadow: none;      backdrop-filter: blur(4px);      -webkit-backdrop-filter: blur(4px);    }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right { right: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-left { left: 0; }    .tg-df-grid-wrapper .tg-df-carousel-scroll-right { right: 0; }        .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-left:hover,    .tg-df-carousel-roundels-wrapper .tg-df-carousel-scroll-right:hover {      background-color: rgba(255, 255, 255, 0.6);      border: none;    }    .tg-df-container .tg-df-carousel-roundels::-webkit-scrollbar {      display: none;    }    .tg-df-container .tg-df-carousel-roundels::after {      content: "";      flex: 0 0 32px;    }    .tg-df-container .tg-df-roundel {      display: flex;      flex-direction: column;      align-items: center;      gap: 8px;      cursor: pointer;      min-width: 120px;      flex-shrink: 0;    }    .tg-df-container .tg-df-roundel-img-box {      width: 120px;      height: 120px;      border-radius: 50%;      background: white;      display: flex;      align-items: center;      justify-content: center;      overflow: hidden;      box-shadow: 0px 3px 14px 0px rgba(30, 41, 59, 0.08);      transition: box-shadow 0.2s;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-img-box {      box-shadow: 0 0 0 2px #E7F0FF, 0 0 0 4px #1F69FF;    }    .tg-df-container .tg-df-roundel:hover .tg-df-roundel-img-box img {      transform: scale(1.08);    }    .tg-df-container .tg-df-roundel-img-box img {      width: 100%;      height: 100%;      object-fit: contain;      padding: 10px;      box-sizing: border-box;      transition: transform 0.3s ease;    }    .tg-df-container .tg-df-roundel-label {      font-size: 13px;      font-weight: 400;      color: #1e293b;      text-align: center;      transition: font-weight 0.2s;    }    .tg-df-container .tg-df-roundel.active .tg-df-roundel-label {      font-weight: 700;    }    .tg-df-container .tg-df-carousel-filters-label {      font-size: 16px;      font-weight: 400;      color: #1e293b;      white-space: nowrap;      margin-right: 4px;    }    .tg-df-container .tg-df-carousel-filters-wrap {      display: flex;      align-items: center;      flex-wrap: nowrap;      gap: 8px;      margin-top: 8px;      overflow-x: auto;      scrollbar-width: none;      -webkit-overflow-scrolling: touch;      padding-bottom: 8px;      margin-left: -24px;      margin-right: -24px;      padding-left: 24px;      padding-right: 24px;    }    .tg-df-container .tg-df-carousel-filters-wrap::-webkit-scrollbar {      display: none;    }        .tg-df-container .tg-df-carousel-filter-btn img,    .tg-df-container .tg-df-carousel-filter-btn picture {      height: 20px;      width: 20px;      object-fit: contain;      object-position: center;      display: inline-flex;      align-items: center;      justify-content: center;      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn picture img {      margin-right: 0;      height: 100%;      width: 100%;    }    .tg-df-container .tg-df-carousel-filter-btn img.active-img,    .tg-df-container .tg-df-carousel-filter-btn picture:has(.active-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.inactive-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.inactive-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.inactive-img) {      display: none;    }    .tg-df-container .tg-df-carousel-filter-btn:hover img.active-img,    .tg-df-container .tg-df-carousel-filter-btn.active img.active-img,    .tg-df-container .tg-df-carousel-filter-btn:hover picture:has(.active-img),    .tg-df-container .tg-df-carousel-filter-btn.active picture:has(.active-img) {      display: inline-flex;    }    .tg-df-container .tg-df-carousel-filter-btn {      background: #ffffff;      border: 2px solid #1e293b;      color: #1e293b;      border-radius: 24px;      padding: 6px 16px;      font-size: 14px;      font-weight: 600;      cursor: pointer;      transition: all 0.2s;      flex-shrink: 0;      white-space: nowrap;      display: inline-flex;      align-items: center;      justify-content: center;      min-height: 36px;      box-sizing: border-box;    }    .tg-df-container .tg-df-carousel-filter-btn svg {      margin-right: 6px;    }    .tg-df-container .tg-df-carousel-filter-btn:hover {      background: #1e293b;      color: white;      border-color: #1e293b;    }    .tg-df-container .tg-df-carousel-filter-btn.active {      background: #1e293b;      color: white;      border-color: #1e293b;    }        .tg-df-grid.carousel-compact {      display: flex;      flex-wrap: nowrap;      overflow-x: auto;      gap: 16px;      padding: 16px 24px;      align-items: stretch;      scrollbar-width: none;    }    .tg-df-grid.carousel-compact::after {      content: "";      flex: 0 0 32px;    }    .tg-df-grid-wrapper {      position: relative;    }    .tg-df-grid.carousel-compact::-webkit-scrollbar {      display: none;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card {      flex: 0 0 auto;      width: 100px;      border-radius: 15px;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      border: 2px solid #1e293b;      background: white;      color: #1e293b;      display: flex;      flex-direction: column;      justify-content: center;      align-items: center;      font-weight: 600;      font-size: 14px;      cursor: pointer;      padding: 16px;      text-align: center;      transition: all 0.2s;    }    .tg-df-grid.carousel-compact .tg-df-load-more-card:hover {      background: #1e293b;      color: white;    }    .tg-df-grid.carousel-compact .tg-df-card {      flex: 0 0 auto;      width: 200px;      min-height: auto;      height: auto;      display: flex;      flex-direction: column;      border-radius: 15px;      border: none;      box-shadow: 0 0 16px rgba(0,0,0,0.08);      overflow: visible;    }    .tg-df-grid.carousel-compact .tg-df-card-image-box {      padding: 12px;      background-color: transparent;      border-radius: 15px 15px 0 0;      height: 130px;    }    .tg-df-grid.carousel-compact .tg-df-card-image {      mix-blend-mode: normal;    }    .tg-df-grid.carousel-compact .tg-df-card-discount-badge {      border-radius: 0;      top: 0px;      left: 0px;      padding: 4px 8px;      font-size: 11px;    }    .tg-df-grid.carousel-compact .tg-df-card-body {      padding: 8px 12px 12px 12px;    }    .tg-df-grid.carousel-compact .tg-df-card-title {      font-size: 14px;      font-weight: 400;      -webkit-line-clamp: 2;      margin-bottom: 8px;      color: #011535;    }    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):not(:has(.tg-df-tag-prime)):not(:has(.tg-df-coupon-wrapper:not([style*="none"]))) > .tg-df-card-title,    .tg-df-grid.carousel-compact .tg-df-card-body:not(:has(.tg-df-card-stars)):has(> .tg-df-card-title:first-child) > .tg-df-card-title {      -webkit-line-clamp: 3;    }    .tg-df-grid.carousel-compact .tg-df-card-cta {      border-radius: 5px;      padding: 8px 10px;      margin-top: 4px;      background-color: #1F69FF;    }    .tg-df-grid.carousel-compact .tg-df-card-price-group {      margin-bottom: 2px;    }    .tg-df-grid.carousel-compact .tg-df-card-merchant-pill {      margin-bottom: 2px;    }    @container tg-df (max-width: 599px) {      .tg-df-container .tg-df-carousel-blue-box-title {        font-size: 24px;      }      .tg-df-container .tg-df-countdown-title {        display: none;      }      .tg-df-container .tg-df-countdown-wrapper {        position: absolute;        top: 0;        right: 0;        align-items: flex-end;        transform: scale(0.45);        transform-origin: top right;      }      .tg-df-container .tg-df-roundel {        min-width: 88px;      }      .tg-df-container .tg-df-roundel-img-box {        width: 88px;        height: 88px;      }    }    /* REPLICA BLOCK STYLES */    .tg-df-grid.layout-replica-2 { grid-template-columns: repeat(2, 1fr) !important; gap: 20px; }    .tg-df-grid.layout-replica-1 { grid-template-columns: 1fr !important; gap: 20px; }        .tg-df-container .hawk-deal-widget-container { border-bottom: 1px solid #e5e7eb; display: flex; flex-direction: column; margin: 0; padding: 20px 0; box-sizing: border-box; font-family: inherit; }    .tg-df-container .hawk-deal-widget-wrap { display: flex; flex-direction: row; align-items: flex-start; width: 100%; gap: 24px; }    .tg-df-container .hawk-deal-widget-image-container { display: flex; flex-shrink: 0; justify-content: center; width: 160px; height: 160px; align-items: center; background: white; margin-bottom: 0px; }    .tg-df-container .hawk-deal-widget-title-product-title { color: #111827; font-size: 18px; font-weight: 700; line-height: 1.4; display: inline; }    .tg-df-container .hawk-deal-widget-title-price { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-price-now { font-weight: 700; }    .tg-df-container .hawk-deal-widget-title-retailer-price:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-title-retailer { font-size: 18px; font-weight: 700; line-height: 1.4; color: #2563eb; }    .tg-df-container .hawk-deal-widget-title-was-price { color: #dc2626; font-size: 16px; font-weight: 500; line-height: 1.4; text-decoration: line-through; white-space: nowrap; margin-left: 8px; margin-right: 8px; }    .tg-df-container .hawk-deal-widget-text-body-container { position: relative; width: 100%; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-text-body-main { font-size: 16px; width: 100%; margin-bottom: 12px; }    .tg-df-container .hawk-deal-widget-text-body-description { display: block; font-size: 15px; margin-top: 12px; color: #4b5563; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-body-description p { margin: 0; line-height: 1.6; }    .tg-df-container .hawk-deal-widget-text-cta-container { display: flex; flex-direction: column; gap: 12px; width: 100%; flex: 1; min-width: 0; box-sizing: border-box; }    .tg-df-container .hawk-deal-widget-footer { display: flex; justify-content: flex-end; width: 100%; margin-top: auto; }    .tg-df-container .hawk-deal-widget-button-wrapper { display: flex; flex-direction: column; align-items: flex-end; justify-content: flex-end; width: 100%; }    .tg-df-container .hawk-deal-widget-preferred-partner-wrapper { display: flex; flex-direction: row; }        @container tg-df (min-width: 600px) {      .tg-df-mobile-only { display: none !important; }    }    @container tg-df (max-width: 599px) {      .tg-df-desktop-only { display: none !important; }      .tg-df-grid.layout-replica-2 { grid-template-columns: 1fr !important; }      .tg-df-grid.savings-squad-cards { grid-template-columns: 1fr !important; display: flex; flex-direction: column; }    }    .tg-df-grid.savings-squad-cards .tg-df-card-title {      -webkit-line-clamp: unset !important;      display: block !important;      overflow: visible !important;    }    @container tg-df (max-width: 500px) {      .tg-df-container .hawk-deal-widget-wrap { display: block; }      .tg-df-container .hawk-deal-widget-image-container { display: block; float: left; margin: 0 16px 8px 0; width: 120px; max-width: 120px; height: auto; align-items: normal; justify-content: normal; }      .tg-df-container .hawk-deal-widget-text-cta-container { display: block; text-align: left; }      .tg-df-container .hawk-deal-widget-footer { display: block; margin-top: 16px; clear: both; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-deal-widget-button-wrapper .hawk-deal-widget-preferred-partner-wrapper { display: block; width: 100%; }      .tg-df-container .hawk-affiliate-link-deal-button { box-sizing: border-box !important; display: flex !important; max-width: none !important; width: 100% !important; margin: 0 !important; }    }        .tg-df-container .hawk-affiliate-link-deal-button {       align-items: center; background-color: #5aaf0b; box-sizing: border-box; color: #ffffff !important; display: flex; font-size: 14px; font-weight: 700; justify-content: center; letter-spacing: 0.5px; line-height: 1; min-width: 160px; padding: 14px 24px; text-align: center; text-decoration: none; text-transform: uppercase; width: 100%; word-break: normal; border-radius: 4px; border: 0; transition: background-color 0.2s;     }    .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #4a9109; text-decoration: none; }    .tg-df-container .hawk-lazy-image-deal-widget { display: block; height: auto; margin: auto; max-height: 160px; max-width: 100%; mix-blend-mode: multiply; object-fit: contain; }    .tg-df-container .hawk-deal-widget-text-cta-container a { color: #2563eb; text-decoration: none; display: inline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover { text-decoration: underline; }    .tg-df-container .hawk-deal-widget-text-cta-container a:has(.hawk-deal-widget-title-product-title) { color: #111827; }    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-product-title,    .tg-df-container .hawk-deal-widget-text-cta-container a:hover .hawk-deal-widget-title-retailer-price { text-decoration: underline; }  \x3C/style>  \x3C!-- Widget Container --\x3E  \x3Cdiv class="tg-df-container" id="signal-deals-finder-root">    \x3C!-- Editor Floating Bar --\x3E    \x3Cdiv class="tg-df-editor-bar" id="tg-df-editor-bar" style="display:none;">      \x3Cdiv class="tg-df-editor-bar-text" style="display: flex; align-items: center;">        \x3Cspan id="tg-df-selected-count">0\x3C/span>\x26nbsp;Deals Selected        \x3Cbutton class="tg-df-editor-clear-btn" id="tg-df-editor-clear" type="button" style="margin-left: 12px; font-size: 13px; color: #9ca3af; background: none; border: none; cursor: pointer; text-decoration: underline;">Clear All\x3C/button>      \x3C/div>      \x3Cbutton class="tg-df-editor-copy-btn" id="tg-df-editor-copy" type="button">        \x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">\x3C/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">\x3C/path>\x3C/svg>        Copy to CMS      \x3C/button>    \x3C/div>    \x3Cdiv class="tg-df-carousel-host" id="tg-df-carousel-host" style="display: none;">      \x3Cdiv class="tg-df-carousel-eyebrow">DEAL FINDER\x3C/div>      \x3Cdiv class="tg-df-carousel-query-title" id="tg-df-carousel-title-label">Best Deals\x3C/div>            \x3Cdiv class="tg-df-carousel-blue-box">        \x3Cdiv class="tg-df-carousel-bg-circle-1" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-2" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-bg-circle-3" aria-hidden="true">\x26nbsp;\x3C/div>        \x3Cdiv class="tg-df-carousel-box-content">          \x3Cdiv class="tg-df-countdown-wrapper" id="tg-df-countdown-wrapper" style="display:none;">            \x3Cdiv class="tg-df-countdown-title" id="tg-df-countdown-title">Prime Day starts in\x3C/div>            \x3Cdiv class="tg-df-countdown-blocks">              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-days">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">DAYS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-hrs">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">HRS\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-min">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">MIN\x3C/div>\x3C/div>              \x3Cdiv class="tg-df-countdown-item">\x3Cdiv class="tg-df-countdown-box">\x3Cdiv class="tg-df-countdown-num" id="tg-df-cd-sec">0\x3C/div>\x3C/div>\x3Cdiv class="tg-df-countdown-label">SEC\x3C/div>\x3C/div>            \x3C/div>          \x3C/div>          \x3Cdiv class="tg-df-carousel-box-eyebrow">DEAL FINDER\x3C/div>          \x3Cdiv class="tg-df-carousel-box-title">Find Deals Fast\x3C/div>          \x3Cdiv class="tg-df-carousel-box-subtitle">The latest deals from the biggest retailers, all in one place\x3C/div>                    \x3Cdiv class="tg-df-carousel-roundels-wrapper">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-roundels">            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>            \x3Cdiv class="tg-df-roundel tg-df-roundel-skeleton">\x3Cdiv class="tg-df-roundel-img-box tg-df-skeleton">\x3C/div>\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="margin: 4px auto 0 auto; height: 13px; width: 48px;">\x3C/div>\x3C/div>          \x3C/div>          \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" onclick="this.parentElement.querySelector('.tg-df-carousel-roundels').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-carousel-filters-outer" style="position: relative;">          \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>          \x3Cdiv class="tg-df-carousel-filters-wrap">                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="0">All\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_lightning">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-ot="amazon_prime">              \x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>            \x3Cbutton class="tg-df-carousel-filter-btn" data-d="10">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 10% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="15">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 15% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-d="25">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>            Min 25% off\x3C/button>                      \x3Cbutton class="tg-df-carousel-filter-btn" data-pr="under50">              \x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>            Under $50\x3C/button>        \x3C/div>        \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('.tg-df-carousel-filters-wrap').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3C/div>    \x3C/div>    \x3C/div>      \x3C!-- Search & Filter Controls --\x3E    \x3Cdiv class="tg-df-controls" id="tg-df-controls" style="display:flex;">      \x3Cdiv class="tg-df-top-bar">        \x3Cdiv class="tg-df-search-wrapper">          \x3Cinput type="text" class="tg-df-search-input" placeholder="Search for deals, products, or brands...">          \x3Cbutton type="button" class="tg-df-search-btn" aria-label="Search">              \x3Csvg class="tg-df-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">                \x3Cpath d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>              \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-autocomplete-dropdown" id="tg-df-autocomplete">\x3C/div>        \x3C/div>                \x3Cdiv class="tg-df-settings-wrapper">          \x3Cbutton type="button" class="tg-df-settings-btn" aria-label="Settings" id="tg-df-settings-toggle">            \x3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">                \x3Cpath d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.73 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .43-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.49-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>            \x3C/svg>          \x3C/button>          \x3Cdiv class="tg-df-settings-dropdown-backdrop" id="tg-df-settings-backdrop">\x3C/div>          \x3Cdiv class="tg-df-settings-dropdown" id="tg-df-settings-panel">            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Search Region\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-region-select">                \x3Coption value="auto">🌍 Auto-detect\x3C/option>                \x3Coption value="US">🇺🇸 United States (US)\x3C/option>                \x3Coption value="GB">🇬🇧 United Kingdom (UK)\x3C/option>                \x3Coption value="CA">🇨🇦 Canada (CA)\x3C/option>                \x3Coption value="AU">🇦🇺 Australia (AU)\x3C/option>                \x3Coption value="DE">🇩🇪 Germany (DE)\x3C/option>                \x3Coption value="FR">🇫🇷 France (FR)\x3C/option>                \x3Coption value="IT">🇮🇹 Italy (IT)\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Retailer\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-retailer-select">                \x3Coption value="">All Retailers\x3C/option>                \x3Coption value="Amazon">Amazon\x3C/option>                \x3Coption value="Walmart">Walmart\x3C/option>                \x3Coption value="Best Buy">Best Buy\x3C/option>                \x3Coption value="Target">Target\x3C/option>                \x3Coption value="John Lewis">John Lewis\x3C/option>                \x3Coption value="Currys">Currys\x3C/option>                \x3Coption value="Argos">Argos\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Offer Type\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-offer-type-select">                \x3Coption value="">All Offers\x3C/option>                \x3Coption value="amazon_prime">Amazon Prime\x3C/option>                \x3Coption value="recommended_promo">Recommended Promo\x3C/option>                \x3Coption value="amazon_lightning">Amazon Lightning Deal\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">Result Count\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-rows-select">                \x3Coption value="3">3 Items\x3C/option>                \x3Coption value="4">4 Items\x3C/option>                \x3Coption value="6">6 Items\x3C/option>                \x3Coption value="12" selected>12 Items\x3C/option>                \x3Coption value="24">24 Items\x3C/option>                \x3Coption value="48">48 Items\x3C/option>              \x3C/select>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Deal Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Only show products with active offers or previous prices (was_price)\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-deal-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item tg-df-dl-row">              \x3Cdiv>                \x3Cspan class="tg-df-dl-row-text">Editor Mode\x3C/span>                \x3Cspan class="tg-df-dl-row-subtext">Enable multi-select to copy deals to CMS\x3C/span>              \x3C/div>              \x3Clabel class="tg-df-toggle">                \x3Cinput type="checkbox" id="tg-df-editor-mode">                \x3Cspan class="tg-df-slider">\x3C/span>              \x3C/label>            \x3C/div>            \x3Cdiv class="tg-df-setting-item">              \x3Clabel class="tg-df-setting-label">View Mode\x3C/label>              \x3Cselect class="tg-df-region-select" id="tg-df-view-mode-select">                \x3Coption value="auto">Auto Collection\x3C/option>                \x3Coption value="carousel">Carousel\x3C/option>                \x3Coption value="savings_squad">Savings Squad\x3C/option>                \x3Coption value="grid">Grid (Columns)\x3C/option>                \x3Coption value="row">Row (List)\x3C/option>              \x3C/select>            \x3C/div>          \x3C/div>        \x3C/div>      \x3C/div>      \x3Cdiv class="tg-df-filters">        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-category-filter-wrapper" style="display: none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-category-filter" aria-label="Category">            \x3Coption value="all">All Categories\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-multiselect-container" id="tg-df-brand-filter-wrapper" style="display:none;">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M4.25 5.61C6.27 8.2 10 13 10 13v6c0 .55.45 1 1 1h2c.55 0 1-.45 1-1v-6s3.72-4.8 5.74-7.39A.998.998 0 0 0 18.95 4H5.04c-.83 0-1.3.95-.79 1.61z"/>          \x3C/svg>          \x3Cdiv class="tg-df-filter-select tg-df-multiselect-trigger" id="tg-df-brand-trigger" tabindex="0">            Any Brand          \x3C/div>          \x3Cdiv class="tg-df-multiselect-dropdown" id="tg-df-brand-dropdown">            \x3C!-- Populated via script --\x3E          \x3C/div>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/>          \x3C/svg>          \x3Cselect class="tg-df-sort-select" aria-label="Sort Deals">            \x3Coption value="date_desc">Newest First\x3C/option>            \x3Coption value="best_match">Sort by: Match\x3C/option>            \x3Coption value="price_asc">Price Low to High\x3C/option>            \x3Coption value="price_desc">Price High to Low\x3C/option>            \x3Coption value="discount_desc">Biggest Discount\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper tg-df-price-range-wrapper" id="tg-df-custom-price-wrapper" style="display: flex; align-items:center; justify-content:center; padding: 10px 20px; gap: 8px; border: 1px solid var(--tg-df-border); border-radius: 100px; background-color: var(--tg-df-bg);">          \x3Cspan style="font-size:14px; font-weight:500; color:var(--tg-df-text-primary);">Price\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-min" placeholder="Min" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">          \x3Cspan style="color:var(--tg-df-text-muted)">-\x3C/span>          \x3Cinput type="number" class="tg-df-price-input" id="tg-df-custom-price-max" placeholder="Max" style="width: 48px; background: transparent; border: none; color: var(--tg-df-text-primary); outline: none; font-size: 14px; text-align: center; padding: 0;">        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-legacy-price-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-price-filter" aria-label="Filter Prices">            \x3Coption value="all">All Prices\x3C/option>            \x3Coption value="under50">Under $50\x3C/option>            \x3Coption value="50_100">$50 - $100\x3C/option>            \x3Coption value="100_200">$100 - $200\x3C/option>            \x3Coption value="200_500">$200 - $500\x3C/option>            \x3Coption value="over500">Over $500\x3C/option>          \x3C/select>        \x3C/div>        \x3Cdiv class="tg-df-sort-wrapper" id="tg-df-discount-filter-wrapper">          \x3Csvg class="tg-df-sort-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">            \x3Cpath d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z"/>          \x3C/svg>          \x3Cselect class="tg-df-filter-select" id="tg-df-discount-filter" aria-label="Discount Amount">            \x3Coption value="all">Any discount\x3C/option>            \x3Coption value="5">Min 5%\x3C/option>            \x3Coption value="10">Min 10%\x3C/option>            \x3Coption value="15">Min 15%\x3C/option>            \x3Coption value="20">Min 20%\x3C/option>            \x3Coption value="25">Min 25%\x3C/option>            \x3Coption value="30">Min 30%\x3C/option>            \x3Coption value="40">Min 40%\x3C/option>            \x3Coption value="50">Min 50%\x3C/option>            \x3Coption value="60">Min 60%\x3C/option>            \x3Coption value="70">Min 70%\x3C/option>          \x3C/select>        \x3C/div>      \x3C/div>    \x3C/div>    \x3C!-- Deals Grid Wrapper --\x3E    \x3Cdiv class="tg-df-grid-wrapper tg-df-carousel-cards-wrapper" id="tg-df-grid-wrapper">      \x3Cbutton class="tg-df-carousel-scroll-left" type="button" aria-label="Scroll left" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: -200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m15 18-6-6 6-6">\x3C/path>\x3C/svg>\x3C/button>      \x3Cdiv class="tg-df-grid" id="tg-df-grid">        \x3C!-- Content populated by JavaScript --\x3E      \x3C/div>      \x3Cbutton class="tg-df-carousel-scroll-right" type="button" aria-label="Scroll right" style="display:none;" onclick="this.parentElement.querySelector('#tg-df-grid').scrollBy({left: 200, behavior: 'smooth'})">\x3Csvg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpath d="m9 18 6-6-6-6">\x3C/path>\x3C/svg>\x3C/button>    \x3C/div>        \x3C!-- Vouchers Modal --\x3E    \x3Cdiv class="tg-df-modal-backdrop" id="tg-df-vouchers-modal">      \x3Cdiv class="tg-df-modal">        \x3Cdiv class="tg-df-modal-header">          \x3Ch3 class="tg-df-modal-title" id="tg-df-vouchers-title">Available Coupons & Deals\x3C/h3>          \x3Cbutton class="tg-df-modal-close" id="tg-df-vouchers-close">            \x3Csvg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">              \x3Cline x1="18" y1="6" x2="6" y2="18">\x3C/line>              \x3Cline x1="6" y1="6" x2="18" y2="18">\x3C/line>            \x3C/svg>          \x3C/button>        \x3C/div>        \x3Cdiv class="tg-df-modal-body" id="tg-df-vouchers-content">          \x3C!-- Vouchers injected here --\x3E        \x3C/div>      \x3C/div>    \x3C/div>  \x3C/div>`;      if (!template) {        template = document.createElement('template');        template.innerHTML = rawTemplate;      }      let shadowRoot = null;      if (hostContainer && template) {        hostContainer.setAttribute('data-initialized', 'true');        shadowRoot = hostContainer.attachShadow({ mode: 'open' });        shadowRoot.appendChild(template.content.cloneNode(true));      }      class DealsFinderWidget {        constructor(config) {          this.rootNode = config.rootNode || document;          this.hostContainer = config.hostContainer || null;          this.rootId = config.rootId || 'signal-deals-finder-root';          this.root = this.rootNode.querySelector('#' + this.rootId);          if (!this.root) return;          this.widgetId = (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'widget-' + Date.now() + '-' + Math.random().toString(36).slice(2);          this.grid = this.root.querySelector('#tg-df-grid');          this.tagsContainer = this.root.querySelector('#tg-df-tags-container');          this.categoryFilter = this.root.querySelector('#tg-df-category-filter');          this.categoryFilterWrapper = this.root.querySelector('#tg-df-category-filter-wrapper');          this.searchInput = this.root.querySelector('.tg-df-search-input');          this.autocompleteDropdown = this.root.querySelector('#tg-df-autocomplete');          this.sortSelect = this.root.querySelector('.tg-df-sort-select');          this.searchBtn = this.root.querySelector('.tg-df-search-btn');                    this.settingsToggle = this.root.querySelector('#tg-df-settings-toggle');          this.settingsPanel = this.root.querySelector('#tg-df-settings-panel');          this.settingsBackdrop = this.root.querySelector('#tg-df-settings-backdrop');          this.regionSelect = this.root.querySelector('#tg-df-region-select');          this.retailerSelect = this.root.querySelector('#tg-df-retailer-select');          this.offerTypeSelect = this.root.querySelector('#tg-df-offer-type-select');          this.viewModeSelect = this.root.querySelector('#tg-df-view-mode-select');          this.rowsSelect = this.root.querySelector('#tg-df-rows-select');          this.dealModeToggle = this.root.querySelector('#tg-df-deal-mode');          this.editorModeToggle = this.root.querySelector('#tg-df-editor-mode');          this.priceFilter = this.root.querySelector('#tg-df-price-filter');          this.discountFilter = this.root.querySelector('#tg-df-discount-filter');                    this.editorBar = this.root.querySelector('#tg-df-editor-bar');          this.editorSelectedCount = this.root.querySelector('#tg-df-selected-count');          this.editorCopyBtn = this.root.querySelector('#tg-df-editor-copy');          this.editorClearBtn = this.root.querySelector('#tg-df-editor-clear');                    this.apiUrl = 'https://search-api.fie.future.net.uk/widget.php';          this.deals = [];          this.displayLimit = 12;          this.airedaleArticles = null;          this.airedaleTags = [];          this.airedaleTagCounts = {};          this.activeDealTag = null;          this.selectedBrands = [];          this.currentQuery = '';          this.editorMode = this.hostContainer ? this.hostContainer.hasAttribute('data-editor-mode') : false;          this.viewModeOverride = this.hostContainer ? this.hostContainer.getAttribute('data-view-mode') : null;          this.selectedDeals = new Map();                    this.brandFilterWrapper = this.root.querySelector('#tg-df-brand-filter-wrapper');          this.brandTrigger = this.root.querySelector('#tg-df-brand-trigger');          this.brandDropdown = this.root.querySelector('#tg-df-brand-dropdown');                    this.customPriceWrapper = this.root.querySelector('#tg-df-custom-price-wrapper');          this.customPriceMin = this.root.querySelector('#tg-df-custom-price-min');          this.customPriceMax = this.root.querySelector('#tg-df-custom-price-max');          this.legacyPriceWrapper = this.root.querySelector('#tg-df-legacy-price-wrapper');          this.discountFilterWrapper = this.root.querySelector('#tg-df-discount-filter-wrapper');          this.initResizeObserver();          this.init();            if (['carousel', 'carousel-compact', 'auto', 'grid', 'row'].includes(this.getViewMode())) { this.loadCarouselSpreadsheet(); }        }        getViewMode() {          if (this.viewModeOverride && (!this.editorMode || !this.viewModeSelect)) {            return this.viewModeOverride;          }          return (this.viewModeSelect && this.viewModeSelect.value) ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');        }        applyLayoutMode() {          if (!this.grid) return;          const mode = this.getViewMode();          this.grid.classList.remove('layout-row', 'layout-grid', 'tg-df-grid-auto', 'carousel-compact', 'layout-replica-1', 'layout-replica-2');                    const carouselHost = this.root.querySelector('#tg-df-carousel-host');          const controlsDiv = this.root.querySelector('#tg-df-controls');          if (mode === 'carousel' || mode === 'auto' || mode === 'grid' || mode === 'row') {             if (mode === 'carousel') this.grid.classList.add('carousel-compact');             if (carouselHost) carouselHost.style.display = 'block';             if (controlsDiv) controlsDiv.style.display = 'none';             if (this.root.classList.contains('tg-df-container') && mode === 'carousel') {               this.root.classList.add('is-carousel');             } else if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          } else {             if (carouselHost) carouselHost.style.display = 'none';             if (controlsDiv) controlsDiv.style.display = 'flex';             if (this.root.classList.contains('tg-df-container')) {               this.root.classList.remove('is-carousel');             }          }          if (mode === 'grid') {            this.grid.classList.add('layout-grid');          } else if (mode === 'row') {            this.grid.classList.add('layout-row');          } else if (mode === 'savings_squad') {            this.grid.classList.add('tg-df-grid-auto', 'savings-squad-cards');          } else if (mode !== 'carousel') {            this.grid.classList.add('tg-df-grid-auto');          }                    const settingsWrapper = this.root.querySelector('.tg-df-settings-wrapper');          if (settingsWrapper) {            settingsWrapper.style.display = mode === 'auto' ? 'none' : 'block';          }          if (this.customPriceWrapper) {             this.customPriceWrapper.style.display = mode === 'auto' ? 'flex' : 'none';          }          if (this.legacyPriceWrapper) {             this.legacyPriceWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }          if (this.discountFilterWrapper) {             this.discountFilterWrapper.style.display = mode === 'auto' ? 'none' : 'flex';          }        }        initResizeObserver() {          try {            if (window.parent === window) return;          } catch (e) {            // cross origin frame check threw          }          const emitHeight = () => {            try {              const height = document.documentElement.scrollHeight || document.body.scrollHeight;              const msg = { type: 'embed-size', height: height };              if (window.parent && window.parent !== window) {                window.parent.postMessage(msg, '*');                window.parent.postMessage(JSON.stringify({ ...msg, sentinel: 'amp' }), '*');              }            } catch (e) {}          };                    if (window.ResizeObserver) {            try {              const ro = new ResizeObserver(() => emitHeight());              ro.observe(document.body);              if (this.root) ro.observe(this.root);            } catch(e){ console.warn(e); }          }          window.addEventListener('resize', emitHeight);          setTimeout(emitHeight, 300);        }        initCountdown() {          this.cdWrapper = this.root.querySelector('#tg-df-countdown-wrapper');                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          this.showCountdown = params.get('show_countdown') === 'true';          const showHeaderDetails = params.get('show_header_details') !== 'false';          const eyebrow = this.root.querySelector('.tg-df-carousel-box-eyebrow');          const title = this.root.querySelector('.tg-df-carousel-box-title');          const subtitle = this.root.querySelector('.tg-df-carousel-box-subtitle');          if (!showHeaderDetails) {            let containerElement = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (containerElement) containerElement.classList.add('hide-header-details');            if (eyebrow) eyebrow.style.display = 'none';            if (title) title.style.display = 'none';            if (subtitle) subtitle.style.display = 'none';          }          if (!this.cdWrapper) return;          this.cdTitle = this.root.querySelector('#tg-df-countdown-title');          this.cdDays = this.root.querySelector('#tg-df-cd-days');          this.cdHrs = this.root.querySelector('#tg-df-cd-hrs');          this.cdMin = this.root.querySelector('#tg-df-cd-min');          this.cdSec = this.root.querySelector('#tg-df-cd-sec');          this.updateCountdown();          this.cdInterval = setInterval(() => this.updateCountdown(), 1000);        }        updateCountdown() {          if (!this.cdWrapper) return;          if (!this.showCountdown) {            this.cdWrapper.style.display = 'none';            return;          }          const area = this.getAreaCode();          let offset = '-04:00';          if (['DE', 'FR', 'IT', 'ES', 'NL'].includes(area)) {             offset = '+02:00';          } else if (['GB', 'IE', 'UK'].includes(area)) {             offset = '+01:00';          }          const startTime = new Date('2026-06-23T00:00:00' + offset).getTime();          const endTime = new Date('2026-06-26T00:00:00' + offset).getTime();          const now = Date.now();          let targetTime = 0;          if (now < startTime) {             targetTime = startTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day starts in';             this.cdWrapper.style.display = 'flex';          } else if (now < endTime) {             targetTime = endTime;             if (this.cdTitle) this.cdTitle.textContent = 'Prime Day ends in';             this.cdWrapper.style.display = 'flex';          } else {             this.cdWrapper.style.display = 'none';             if (this.cdInterval) clearInterval(this.cdInterval);             return;          }          const diff = Math.max(0, targetTime - now);          const d = Math.floor(diff / (1000 * 60 * 60 * 24));          const h = Math.floor((diff / (1000 * 60 * 60)) % 24);          const m = Math.floor((diff / 1000 / 60) % 60);          const s = Math.floor((diff / 1000) % 60);          if (this.cdDays) this.cdDays.textContent = d;          if (this.cdHrs) this.cdHrs.textContent = h;          if (this.cdMin) this.cdMin.textContent = m;          if (this.cdSec) this.cdSec.textContent = s;        }        init() {          this.initCountdown();          try {            initAnalytics();          } catch (e) {            console.warn('Deals Widget Analytics Error:', e);          }                    this.bindEvents();                    let initialQuery = '';                    let searchSource = window.location.search;          if (this.hostContainer && this.hostContainer.hasAttribute('data-widget-config')) {            searchSource = this.hostContainer.getAttribute('data-widget-config');          } else if (typeof window !== 'undefined' && window.__WIDGET_CONFIG__) {            searchSource = window.__WIDGET_CONFIG__;          }          const params = new URLSearchParams(searchSource);          let initialViewMode = params.get('view_mode');          if (!params.has('search') && !params.has('q') && !params.has('query') && initialViewMode !== 'savings_squad') {             initialQuery = 'Everything';             if (this.discountFilter && !params.has('min_discount_ratio')) {               this.discountFilter.value = '5';             }          }          const website = params.get('website') || 'tomsguide';          this.website = website;          if (website === 'techradar') {            const squadHeader = this.root.querySelector('.tg-df-savings-squad-header');            if (squadHeader) {               const pic = squadHeader.querySelector('picture');               if (pic) pic.style.display = 'none';            }            const style = document.createElement('style');            style.innerHTML = `              .tg-df-container .hawk-affiliate-link-deal-button { background-color: #5DAF08 !important; }              .tg-df-container .hawk-affiliate-link-deal-button:hover { background-color: #4a8c06 !important; }            `;            this.root.appendChild(style);          }                    if (this.regionSelect) {            this.regionSelect.value = params.get('region') || 'auto';            this.updatePriceDropdownCurrency();          }                    if (this.retailerSelect && params.has('retailer')) {            this.retailerSelect.value = params.get('retailer');          }                    if (params.has('brands')) {            const b = params.get('brands');            if (b) {              this.selectedBrands = b.split(',');            }          }                    if (this.offerTypeSelect && params.has('offer_type')) {            this.offerTypeSelect.value = params.get('offer_type');          }          if (params.has('bg_color')) {            const bg = params.get('bg_color');            if (bg === 'white') {              this.root.style.setProperty('background-color', '#ffffff', 'important');            } else if (bg === 'transparent') {              this.root.style.setProperty('background-color', 'transparent', 'important');            } else if (bg === 'light_blue') {              this.root.style.setProperty('background-color', '#E7F0FF', 'important');            }          } else {             this.root.style.removeProperty('background-color');          }                    if (params.has('view_mode')) {            if (this.viewModeSelect) {              this.viewModeSelect.value = params.get('view_mode');            } else {              this.viewModeOverride = params.get('view_mode');            }          }          if (this.rowsSelect && params.has('rows')) {            this.rowsSelect.value = params.get('rows');          }          if (params.has('price')) {            const priceVal = params.get('price');            if (this.priceFilter) {               // Try assigning it directly to select. If it's not present implicitly ignores               this.priceFilter.value = priceVal;            }            if (priceVal.includes('_')) {               const parts = priceVal.split('_');               if (this.customPriceMin && parts[0]) this.customPriceMin.value = parts[0];               if (this.customPriceMax && parts[1]) this.customPriceMax.value = parts[1];            }          }          if (this.discountFilter && params.has('min_discount_ratio')) {            // Need to convert back from ratio (e.g. 0.8) to select value (e.g. "20")            const ratioStr = params.get('min_discount_ratio');            const ratioFloat = parseFloat(ratioStr);            if (!isNaN(ratioFloat)) {               const percentage = Math.round((1 - ratioFloat) * 100);               this.discountFilter.value = percentage.toString();            }          }          if (this.sortSelect) {            this.sortSelect.value = params.get('sort') || 'discount_desc';          }          if (this.dealModeToggle && params.has('deal_mode')) {            this.dealModeToggle.checked = params.get('deal_mode') === 'true' || params.get('deal_mode') === '1';          }                    // Re-apply layout after params have updated control values          this.applyLayoutMode();                    if (params.get('search')) {            initialQuery = params.get('search');          } else if (params.get('q')) {            initialQuery = params.get('q');          } else if (params.get('query')) {            initialQuery = params.get('query');          }                    this.currentQuery = initialQuery;          if (this.searchInput) {            this.searchInput.value = this.currentQuery;          }                    if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {            this.fetchDeals(this.currentQuery);          } else {            this.render();          }        }        updatePriceDropdownCurrency() {          if (!this.priceFilter || !this.regionSelect) return;          const currencySymbols = {            'US': '$',            'GB': '£',            'CA': '$CA',            'AU': '$AU',            'DE': '€',            'FR': '€',            'IT': '€',          };          const area = this.getAreaCode();          const cur = currencySymbols[area || 'US'] || '$';                    const options = this.priceFilter.options;          for (let i = 0; i < options.length; i++) {            const opt = options[i];            if (opt.value === 'all') {              opt.innerText = 'All Prices';            } else if (opt.value === 'under50') {              opt.innerText = `Under ${cur}50`;            } else if (opt.value === '50_100') {              opt.innerText = `${cur}50 - ${cur}100`;            } else if (opt.value === '100_200') {              opt.innerText = `${cur}100 - ${cur}200`;            } else if (opt.value === '200_500') {              opt.innerText = `${cur}200 - ${cur}500`;            } else if (opt.value === 'over500') {              opt.innerText = `Over ${cur}500`;            }          }        }        populateBrandDropdown(values) {          if (!this.brandDropdown || !this.brandFilterWrapper) return;          this.brandFilterWrapper.style.display = 'flex'; // show the wrapper                    let html = '';          const allChecked = this.selectedBrands.length === 0 ? 'checked' : '';          const _div = '<' + '/div>';          const _span = '<' + '/span>';          html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="" ${allChecked} class="tg-df-brand-chk"> Any Brand${_div}`;                    values.forEach(v => {             if (!v.formatted_value || v.formatted_value === 'Any Brand') return;             const isChecked = this.selectedBrands.includes(v.formatted_value) ? 'checked' : '';             html += `\x3Cdiv class="tg-df-ms-option">\x3Cinput type="checkbox" value="${this.escapeHTML(v.formatted_value)}" ${isChecked} class="tg-df-brand-chk"> ${this.escapeHTML(v.formatted_value)} \x3Cspan style="color:var(--tg-df-text-muted);font-size:12px">(${v.count || 0})${_span}${_div}`;          });                    this.brandDropdown.innerHTML = html;                    // Re-bind listeners          const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');          chks.forEach(chk => {            chk.addEventListener('change', (e) => {              const val = e.target.value;              if (val === '') {                this.selectedBrands = [];              } else {                if (e.target.checked) {                   if (!this.selectedBrands.includes(val)) this.selectedBrands.push(val);                } else {                   this.selectedBrands = this.selectedBrands.filter(b => b !== val);                }              }                            if (this.selectedBrands.length === 0) {                 this.brandTrigger.innerText = 'Any Brand';              } else if (this.selectedBrands.length === 1) {                 this.brandTrigger.innerText = this.selectedBrands[0];              } else {                 this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;              }                            // Only call API if changed from UI interactions              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.updateURLParams();                 this.fetchDeals(this.currentQuery);              }            });          });                    // Update button text on load          if (this.selectedBrands.length === 0) {             this.brandTrigger.innerText = 'Any Brand';          } else if (this.selectedBrands.length === 1) {             this.brandTrigger.innerText = this.selectedBrands[0];          } else {             this.brandTrigger.innerText = `${this.selectedBrands.length} Brands selected`;          }        }        updateURLParams() {          const url = new URL(window.location);          if (this.currentQuery && this.currentQuery !== 'Gaming laptops') {            url.searchParams.set('q', this.currentQuery);          } else {            url.searchParams.delete('q');            url.searchParams.delete('search');            url.searchParams.delete('query');          }                    if (this.regionSelect && this.regionSelect.value !== 'auto') {            url.searchParams.set('region', this.regionSelect.value);          } else {            url.searchParams.delete('region');          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.set('retailer', this.retailerSelect.value);          } else {            url.searchParams.delete('retailer');          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.set('brands', this.selectedBrands.join(','));          } else {            url.searchParams.delete('brands');          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.set('offer_type', this.offerTypeSelect.value);          } else {            url.searchParams.delete('offer_type');          }                    if (this.viewModeSelect && this.viewModeSelect.value !== 'auto') {            url.searchParams.set('view_mode', this.viewModeSelect.value);          } else {            url.searchParams.delete('view_mode');          }                    if (this.rowsSelect && this.rowsSelect.value !== '12') {            url.searchParams.set('rows', this.rowsSelect.value);          } else {            url.searchParams.delete('rows');          }                    const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             url.searchParams.set('price', `${min}_${max}`);          } else if (this.priceFilter && this.priceFilter.value !== 'all') {            url.searchParams.set('price', this.priceFilter.value);          } else {            url.searchParams.delete('price');          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {               const ratio = (100 - v) / 100;               url.searchParams.set('min_discount_ratio', ratio.toString());            }          } else {            url.searchParams.delete('min_discount_ratio');          }                    if (this.sortSelect && this.sortSelect.value !== 'discount_desc') {            url.searchParams.set('sort', this.sortSelect.value);          } else {            url.searchParams.delete('sort');          }                    if (this.dealModeToggle && this.dealModeToggle.checked) {            url.searchParams.set('deal_mode', 'true');          } else {            url.searchParams.delete('deal_mode');          }                    window.history.replaceState({}, '', url);        }        bindEvents() {          const roundels = this.root.querySelectorAll('.tg-df-carousel-cat.original-hardcoded');          roundels.forEach(r => {             r.addEventListener('click', () => {                const q = r.getAttribute('data-query');                const pr = r.getAttribute('data-pr');                if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: q,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = q;                const label = this.root.querySelector('#tg-df-carousel-title-label');                if (label) label.textContent = 'Best ' + q;                if (this.priceFilter) this.priceFilter.value = pr || 'all';                if (this.discountFilter) this.discountFilter.value = '5';                if (this.searchInput) this.searchInput.value = q;                                roundels.forEach(ro => ro.classList.remove('active'));                r.classList.add('active');                this.fetchDeals(this.currentQuery);             });          });          const discBtns = this.root.querySelectorAll('.tg-df-carousel-filter-btn');          discBtns.forEach(b => {             b.addEventListener('click', () => {                const d = b.getAttribute('data-d');                const pr = b.getAttribute('data-pr');                const ot = b.getAttribute('data-ot');                let label = b.innerText ? b.innerText.trim() : '';                let filterType = 'unknown';                let filterVal = 'unknown';                if (d !== null) { filterType = 'discount'; filterVal = d; }                else if (pr !== null) { filterType = 'price'; filterVal = pr; }                else if (ot !== null) { filterType = 'offertype'; filterVal = ot; }                if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-${filterType}-${filterVal}`, name: 'Filter Button', label: label });                                if (d !== null) {                   if (this.discountFilter) this.discountFilter.value = this.discountFilter.value === d ? '0' : d;                } else if (pr !== null) {                   if (this.priceFilter) this.priceFilter.value = this.priceFilter.value === pr ? 'all' : pr;                } else if (ot !== null) {                   if (this.offerTypeSelect) this.offerTypeSelect.value = this.offerTypeSelect.value === ot ? 'all' : ot;                } else {                   if (this.discountFilter) this.discountFilter.value = '0';                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.offerTypeSelect) this.offerTypeSelect.value = 'all';                }                if (d === null && pr === null && ot === null && b.getAttribute("data-type") !== "custom") {                   discBtns.forEach(ro => ro.classList.remove('active'));                   b.classList.add('active');                } else if (b.getAttribute("data-type") !== "custom") {                   // Only operate on hardcoded buttons (those without data-type)                   discBtns.forEach(ro => {                      if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active');                   });                                      let makeActive = true;                   if (d !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-d') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (pr !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-pr') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   } else if (ot !== null) {                       if (b.classList.contains('active')) makeActive = false;                       discBtns.forEach(ro => { if (ro.getAttribute('data-ot') !== null && ro.getAttribute('data-type') !== 'custom') ro.classList.remove('active') });                   }                                      if (makeActive) b.classList.add('active');                                      // Check if anything is active, if not activate "All"                   let anyActive = false;                   discBtns.forEach(ro => { if (ro.classList.contains('active') && ro.getAttribute('data-type') !== 'custom') anyActive = true; });                   if (!anyActive) {                       discBtns.forEach(ro => { if (!ro.getAttribute('data-d') && !ro.getAttribute('data-pr') && !ro.getAttribute('data-ot') && ro.getAttribute('data-type') !== 'custom') ro.classList.add('active'); });                   }                }                                this.fetchDeals(this.currentQuery);             });          });          if (this.brandTrigger && this.brandDropdown) {            this.brandTrigger.addEventListener('click', () => {              this.brandDropdown.classList.toggle('active');            });            document.addEventListener('click', (e) => {              if (this.brandFilterWrapper && !e.composedPath().includes(this.brandFilterWrapper)) {                this.brandDropdown.classList.remove('active');              }            });          }          let debounceTimer;          if(this.searchInput) {            this.searchInput.addEventListener('input', (e) => {              clearTimeout(debounceTimer);              const query = e.target.value.trim();              this.currentQuery = query;              if (this.getViewMode() === 'savings_squad' && this.autocompleteDropdown && this.airedaleTags && query.length > 0) {                 const matches = this.airedaleTags.filter(t => t.toLowerCase().includes(query.toLowerCase()) && t.toLowerCase() !== query.toLowerCase()).slice(0, 5);                 if (matches.length > 0) {                    this.autocompleteDropdown.innerHTML = matches.map(m => `\x3Cdiv class="tg-df-autocomplete-item" data-tag="${this.escapeHTML(m)}">${this.escapeHTML(m)}<` + `/div>`).join('');                    this.autocompleteDropdown.classList.add('active');                 } else {                    this.autocompleteDropdown.classList.remove('active');                 }              } else if (this.autocompleteDropdown) {                 this.autocompleteDropdown.classList.remove('active');              }              debounceTimer = setTimeout(() => {                this.updateURLParams();                if (query.length > 2) {                  this.fetchDeals(query);                } else if (query.length === 0) {                  this.deals = [];                  this.render();                }              }, 400);            });            this.searchInput.addEventListener('keypress', (e) => {              if (e.key === 'Enter') {                if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');                clearTimeout(debounceTimer);                const query = e.target.value.trim();                this.currentQuery = query;                this.activeDealTag = null;                trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });                this.updateURLParams();                if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                   this.fetchDeals(query);                }              }            });          }          if (this.autocompleteDropdown) {             this.autocompleteDropdown.addEventListener('click', (e) => {                const item = e.target.closest('.tg-df-autocomplete-item');                if (item) {                   const tag = item.getAttribute('data-tag');                   this.currentQuery = tag;                   if (this.searchInput) this.searchInput.value = tag;                   this.activeDealTag = tag;                   this.autocompleteDropdown.classList.remove('active');                   this.updateURLParams();                   this.fetchDeals(tag);                }             });             document.addEventListener('click', (e) => {               if (this.autocompleteDropdown && this.searchInput && !e.composedPath().includes(this.searchInput) && !e.composedPath().includes(this.autocompleteDropdown)) {                 this.autocompleteDropdown.classList.remove('active');               }             });          }          if (this.searchBtn) {            this.searchBtn.addEventListener('click', () => {              if (this.autocompleteDropdown) this.autocompleteDropdown.classList.remove('active');              clearTimeout(debounceTimer);              const query = this.searchInput.value.trim();              trackElementInteraction({ id: 'search-submit', name: 'Ask', label: 'Ask (main search)', text: query });              this.activeDealTag = null;              this.currentQuery = query;              this.updateURLParams();              if (query.length > 2 || (this.getViewMode() === 'savings_squad')) {                 this.fetchDeals(query);              }            });          }          if(this.sortSelect) this.sortSelect.addEventListener('change', () => {            trackElementInteraction({ id: `sort-option-${this.sortSelect.value}`, name: 'Sort', label: `Sort: ${this.sortSelect.options[this.sortSelect.selectedIndex].text}` });            this.updateURLParams();            if (this.deals.length > 0) {              this.sortData();              this.render();            }          });                    const priceFilter = this.root.querySelector('#tg-df-price-filter');          if (priceFilter) {            this.priceFilter = priceFilter;            this.priceFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-price-${this.priceFilter.value}`, name: 'Price', label: this.priceFilter.options[this.priceFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          const updateCustomPrice = () => {             this.updateURLParams();             if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);             } else {                this.render();             }          };          if (this.customPriceMin) {             this.customPriceMin.addEventListener('change', updateCustomPrice);             this.customPriceMin.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          if (this.customPriceMax) {             this.customPriceMax.addEventListener('change', updateCustomPrice);             this.customPriceMax.addEventListener('keypress', (e) => {                if (e.key === 'Enter') updateCustomPrice();             });          }          const discountFilter = this.root.querySelector('#tg-df-discount-filter');          if (discountFilter) {            this.discountFilter = discountFilter;            this.discountFilter.addEventListener('change', () => {              trackElementInteraction({ id: `filter-discount-${this.discountFilter.value}`, name: 'Discount', label: this.discountFilter.options[this.discountFilter.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }            });          }          if (this.categoryFilter) {            this.categoryFilter.addEventListener('change', (e) => {               const val = e.target.value === 'all' ? null : e.target.value;               this.activeDealTag = val;               this.fetchSavingsSquad();            });          }                    if (this.settingsToggle) {            this.settingsToggle.addEventListener('click', () => {              const o = this.settingsPanel.classList.toggle('active');              this.settingsBackdrop.classList.toggle('active');              if (o) trackElementInteraction({ id: 'filter-open', name: 'Filters', label: 'Open filters' });            });          }                    if (this.settingsBackdrop) {            this.settingsBackdrop.addEventListener('click', () => {              this.settingsPanel.classList.remove('active');              this.settingsBackdrop.classList.remove('active');            });          }                    if (this.regionSelect) {            this.regionSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-region-${this.regionSelect.value}`, name: 'Region', label: this.regionSelect.options[this.regionSelect.selectedIndex].text });              this.updateURLParams();              this.updatePriceDropdownCurrency();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.retailerSelect) {            this.retailerSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-merchant-${this.retailerSelect.value}`, name: 'Retailer', label: this.retailerSelect.options[this.retailerSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.offerTypeSelect) {            this.offerTypeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-offertype-${this.offerTypeSelect.value}`, name: 'Offer Type', label: this.offerTypeSelect.options[this.offerTypeSelect.selectedIndex].text });              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.viewModeSelect) {            this._prevViewMode = this.viewModeSelect.value;            this.viewModeSelect.addEventListener('change', () => {              trackElementInteraction({ id: `filter-viewmode-${this.viewModeSelect.value}`, name: 'View Mode', label: this.viewModeSelect.options[this.viewModeSelect.selectedIndex].text });                            // Reset all active toggles and filters to prevent config carry-over              this.selectedBrands = [];              if (this.brandTrigger) this.brandTrigger.innerText = 'Select Brands';              if (this.brandDropdown) {                const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                chks.forEach(chk => { chk.checked = false; });              }              if (this.priceFilter) this.priceFilter.value = 'all';              if (this.customPriceMin) this.customPriceMin.value = '';              if (this.customPriceMax) this.customPriceMax.value = '';              if (this.sortSelect) this.sortSelect.value = this.viewModeSelect.value === 'savings_squad' ? 'date_desc' : 'discount_desc';              if (this.discountFilter) this.discountFilter.value = '0';              if (this.retailerSelect) this.retailerSelect.value = '';              if (this.offerTypeSelect) this.offerTypeSelect.value = '';              if (this.rowsSelect) this.rowsSelect.value = '12';              if (this.categoryFilter) this.categoryFilter.value = 'all';              this.activeDealTag = null;              this.updateURLParams();              this.applyLayoutMode();                            if (this.getViewMode() === 'savings_squad' || this._prevViewMode === 'savings_squad') {                this.fetchDeals(this.currentQuery);              } else {                this.render();              }              this._prevViewMode = this.viewModeSelect.value;            });          }                    if (this.rowsSelect) {            this.rowsSelect.addEventListener('change', () => {              this.updateURLParams();              if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {                this.fetchDeals(this.currentQuery);              }            });          }                    if (this.dealModeToggle) {            this.dealModeToggle.addEventListener('change', () => {              this.updateURLParams();              this.render();            });          }          if (this.editorModeToggle) {             this.editorModeToggle.addEventListener('change', (e) => {                this.editorMode = e.target.checked;                this.render();                this.updateFloatingCopyBar();             });          }          if (this.editorCopyBtn) {             this.editorCopyBtn.addEventListener('click', () => {                this.copySelectedDealsToCMS();             });          }          if (this.editorClearBtn) {             this.editorClearBtn.addEventListener('click', () => {                this.selectedDeals.clear();                this.render();                this.updateFloatingCopyBar();             });          }          if (this.grid) {            this.grid.addEventListener('change', (e) => {               if (e.target.classList.contains('tg-df-deal-checkbox')) {                  const dealId = e.target.getAttribute('data-id');                  if (e.target.checked) {                     const dealObj = this.deals.find(d => d.id === dealId);                     if (dealObj) this.selectedDeals.set(dealId, dealObj);                  } else {                     this.selectedDeals.delete(dealId);                  }                  this.updateFloatingCopyBar();               }            });            this.grid.addEventListener('click', (e) => {              const dealCard = e.target.closest('[data-action="deal-click"]');              const similarCard = e.target.closest('[data-action="view-similar-click"]');              const cardLink = dealCard || similarCard;              if (cardLink) {                const productName = cardLink.getAttribute('data-product-name');                const merchantName = cardLink.getAttribute('data-merchant-name');                const productId = cardLink.getAttribute('data-analytics-id');                const price = parseFloat(cardLink.getAttribute('data-price')) || null;                const prevPriceStr = cardLink.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = cardLink.getAttribute('data-original-link');                const rewrittenLink = cardLink.getAttribute('href');                const revenueId = cardLink.getAttribute('data-revenue-id');                const index = parseInt(cardLink.getAttribute('data-index'), 10) || 0;                const inStock = cardLink.getAttribute('data-in-stock') === 'true';                const totalText = cardLink.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: cardLink.getAttribute('data-model-id') || null,                    matchId: cardLink.getAttribute('data-match-id') || null,                    brand: cardLink.getAttribute('data-model-brand') || null,                    parent: cardLink.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: cardLink.getAttribute('data-merchant-id') || null,                    network: cardLink.getAttribute('data-merchant-network') || null,                    url: cardLink.getAttribute('data-merchant-url') || null,                    name: merchantName                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: normalizeCurrency(this.escapeHTML(cardLink.getAttribute('data-currency') || '$'))                };                if (dealCard) {                  trackDealClick(trackingParams);                } else {                  trackViewSimilarClick(trackingParams);                }              }              const couponsBtn = e.target.closest('[data-action="coupons-click"]');              if (couponsBtn) {                trackElementInteraction({                  id: 'product-card-show-coupons',                  name: 'Coupons',                  label: `Product card coupons: ${couponsBtn.getAttribute('data-merchant')}`                });              }            });          }          this.setupScrollListeners();        }        setupScrollListeners() {          const containers = [             this.root.querySelector('.tg-df-carousel-roundels'),             this.root.querySelector('.tg-df-carousel-filters-wrap'),             this.root.querySelector('#tg-df-grid')          ];                    containers.forEach(container => {             if (!container) return;                          const checkScroll = () => {                if (!container.parentElement) return;                const leftBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-left');                const rightBtn = container.parentElement.querySelector('.tg-df-carousel-scroll-right');                                if (leftBtn) {                   if (container.scrollLeft <= 5) leftBtn.style.display = 'none';                   else leftBtn.style.display = 'flex';                }                                if (rightBtn) {                   if (container.scrollWidth <= container.clientWidth) {                       rightBtn.style.display = 'none';                   } else if (container.scrollLeft >= container.scrollWidth - container.clientWidth - 5) {                       rightBtn.style.display = 'none';                   } else {                       rightBtn.style.display = 'flex';                   }                }             };                          container.addEventListener('scroll', checkScroll);             checkScroll();                          window.addEventListener('resize', checkScroll);                          const observer = new MutationObserver(checkScroll);             observer.observe(container, { childList: true, subtree: true, characterData: false });          });        }        get widgetTypeName() {          const mode = this.viewModeSelect ? this.viewModeSelect.value : (this.viewModeOverride || 'auto');          switch(mode) {              case 'carousel': return 'Carousel';              case 'savings_squad': return 'Savings Squad';              case 'grid': return 'Grid';              case 'row': return 'Row';              default: return 'Auto Collection';          }        }        getAreaCode() {          if (this.regionSelect && this.regionSelect.value) {            if (this.regionSelect.value === 'auto') return null;            return this.regionSelect.value;          }          let area = null;          try {            const locale = window.navigator.language || window.navigator.userLanguage;            if (locale && locale.includes('-')) {              area = locale.split('-')[1].toUpperCase();            } else if (locale && locale.length === 2) {              if (locale.toUpperCase() === 'EN') { area = 'US'; }              else { area = locale.toUpperCase(); }            }          } catch (e) { /* Ignore */ }                    // Map to known valid options or fallback to US          const valid = ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'IT'];          if (area === 'UK') area = 'GB';          if (valid.includes(area)) {             return area;          }          return 'US';        }                async loadCarouselSpreadsheet() {          try {              const parseCSVRow = (str) => {                  let result = [], cur = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (inQuotes) {                          if (char === '"') {                              if (str[i + 1] === '"') { cur += '"'; i++; }                              else { inQuotes = false; }                          } else { cur += char; }                      } else {                          if (char === '"') { inQuotes = true; }                          else if (char === ',') { result.push(cur); cur = ''; }                          else { cur += char; }                      }                  }                  result.push(cur); return result;              };              const parseCSV = (str) => {                  const rows = []; let curRow = '', inQuotes = false;                  for (let i = 0; i < str.length; i++) {                      let char = str[i];                      if (char === '"') inQuotes = !inQuotes;                      if ((char === '\n' || char === '\r') && !inQuotes) {                          if (char === '\r' && str[i+1] === '\n') i++;                          if (curRow) rows.push(parseCSVRow(curRow));                          curRow = '';                      } else { curRow += char; }                  }                  if (curRow) rows.push(parseCSVRow(curRow));                  return rows;              };              const preloadedCSV = decodeURIComponent(escape(atob("LCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNQ0KUm91bmRlbCB0ZXh0LEFsbCxUVnMsRm9vdHdlYXIsQXBwYXJlbCxNYXR0cmVzZXMsQXBwbGlhbmNlcyxXZWFyYWJsZSB0ZWNoLEhlYWRwaG9uZXMsU21hcnQgSG9tZSxTcGVha2VycyxMYXB0b3BzLFRhYmxldHMsQ29tcHV0aW5nLFBob25lcyxHYW1pbmcsTGVnbw0KUm91bmRlbCBpbWFnZSxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2FpLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3R2cy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvN2IzYTIyNGIwNzk2M2M2MjdiNmI5MDliZDc4MzM4MzZlMDJmZjgxOS5qcGcud2VicCxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy84NGRhYzVkNDhlZDJkNDQ4NTU5ZWJhNjdhY2U4MzE0Y2M2N2NjZDk0LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvbWF0dHJlc3Nlcy5wbmcsaHR0cHM6Ly9pbWFnZXMuZmllLmZ1dHVyZWNkbi5uZXQvcHJvZHVjdHMvNzY4ZTk3Y2ViMDcxODAxZmFlMjA5MTBkMDgyMGIxNmY3NDdhZjkzOS5qcGcud2VicCxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3dlbGxuZXNzLnBuZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL2hlYWRwaG9uZXMuanBnLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzg5NTM1YmVlYmUyMGRiYmQ0YTM0NmQ2ZDZiZGZlOTFkOGE4ODRhMjEuanBnLndlYnAsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9hdWRpby5qcGcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9sYXB0b3BzLmpwZyxodHRwczovL2ltYWdlcy5maWUuZnV0dXJlY2RuLm5ldC9wcm9kdWN0cy8yMzk3NTY0ZWQ3YTVmZjk0N2U5YjZiMzBlNTRmNDc0OTRiODQxZjg5LmpwZy53ZWJwLGh0dHBzOi8vd3d3LnRvbXNndWlkZS5jb20vcHJvZHVjdHMvY2Fyb3VzZWwvY29tcHV0aW5nLmpwZyxodHRwczovL3d3dy50b21zZ3VpZGUuY29tL3Byb2R1Y3RzL2Nhcm91c2VsL3Bob25lcy5wbmcsaHR0cHM6Ly93d3cudG9tc2d1aWRlLmNvbS9wcm9kdWN0cy9jYXJvdXNlbC9nYW1pbmcucG5nLGh0dHBzOi8vaW1hZ2VzLmZpZS5mdXR1cmVjZG4ubmV0L3Byb2R1Y3RzLzRmNmM2MjFjYWMwYmMxYTg1ZDU5M2UzNTk0YmE1YjM0OWVmZmQyOTIuanBnLndlYnANClNlYXJjaCBRdWVyeSxFdmVyeXRoaW5nLFRlbGV2aXNpb25zLCJTbmVha2VycywgcnVubmluZyBzaG9lcywgc2FuZGFscyIsQ2xvdGhpbmcsTWF0dHJlc3NlcyxIb21lIEFwcGxpYW5jZXMsV2VhcmFibGVzICYgRml0bmVzcyBUZWNoLEhlYWRwaG9uZXMsSG9tZSBUZWNoLFNwZWFrZXJzLExhcHRvcHMsVGFibGV0cyxDb21wdXRpbmcsUGhvbmVzLEdhbWluZyxDb25zdHJ1Y3Rpb24gVG95cw0KRGlzY291bnQgQW1vdW50LG1pbiA1JSxtaW4gMTAlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUsbWluIDUlLG1pbiA1JSxtaW4gNSUNClByaWNlIFJhbmdlLCwsLCxtaW4gJDQwMCwsLCxtaW4gJDI1LCxtaW4gJDMwMCwsLG1pbiAkMTAwLCwNCkJyYW5kIFNlbGVjdGlvbiwsLCwsLCwsLCwsLCwsLCwNCkZpbHRlciBidXR0b25zLCwsLCwsLCwsLCwsLCwsLA0KMSxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMsTGlnaHRuaW5nIGRlYWxzLExpZ2h0bmluZyBkZWFscyxMaWdodG5pbmcgZGVhbHMNCjIsQW1hem9uIGRlYWxzLFVuZGVyICQxMDAwLDUwJSBvZmYsQWRpZGFzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsNTAlIG9mZixBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscyxBbWF6b24gZGVhbHMsQW1hem9uIGRlYWxzLEFtYXpvbiBkZWFscw0KMyxPdmVyICQ0MDAsVW5kZXIgJDUwMCxIb2thLE5pa2UsU2FhdHZhLE5pbmphLDQwJSBvZmYsSkxhYiwsSkJMLERlbGwsLEFzdXMsQXBwbGUsQ29uc29sZXMsU3RhciBXYXJzDQo0LFVuZGVyICQxMDAwLDUwJSBvZmYsU2tlY2hlcnMsVW5kZXIgQXJtb3VyLEhlbGl4LFNoYXJrLEdhcm1pbixBbmtlciBTb3VuZGNvcmUsUmluZyxTb25vcyxBcHBsZSxBcHBsZSxUUC1saW5rLFNhbXN1bmcsQWNjZXNzb3JpZXMsVW5kZXIgJDI1DQo1LFVuZGVyICQ1MDAsTEcsQXNpY3MsQ29sdW1iaWEsRHJlYW1DbG91ZCxLZXVyaWcsQXBwbGUsU29ueSxHb3ZlZSxUcmliaXQsTGVub3ZvLFNhbXN1bmcsRWVybyxHb29nbGUsR2FtZXMsVW5kZXIgJDUwDQo2LDUwJSBvZmYsU2Ftc3VuZyxOaWtlLFBhdGFnb25pYSxOZWN0YXIsRGUnTG9uZ2hpLEFtYXpmaXQsQXBwbGUsS2FzYSBzbWFydCxTb255LEFsaWVud2FyZSxUQ0wsTmV0Z2VhcixNb3Rvcm9sYSxOaW50ZW5kbyxCb3RhbmljYWxzDQo3LEFtYXpvbixIaXNlbnNlLE5ldyBCYWxhbmNlLEFyYyd0ZXJ5eCxUZW1wdXItcGVkaWMsRHlzb24sRml0Yml0LEJlYXRzLFBoaWxpcHMgSHVlLEFua2VyLEFjZXIsT25lUGx1cyxEZWxsLE9uZVBsdXMsU29ueSxEaXNuZXkNCjgsQXBwbGUsVENMLEFkaWRhcyxDYXJoYXJ0dCxCZWFyLEJpc3NlbGwsU2Ftc3VuZyxFYXJmdW4sQmxpbmssQmVhdHMsTVNJLE1pY3Jvc29mdCxBY2VyLE5vdGhpbmcsWGJveCxNYXJ2ZWwNCjksLFNvbnksU2F1Y29ueSxUaGUgTm9ydGggRmFjZSxTaWVuYSxOdXRyaWJ1bGxldCxPdXJhLFNhbXN1bmcsR29vZ2xlIE5lc3QgLE1hcnNoYWxsLFNhbXN1bmcsTGVub3ZvLExlbm92bywsLFBva2Vtb24NCjEwLCxSb2t1LEJpcmtlbnN0b2NrLENSWiBZb2dhLFdpbmtCZWRzLEJsYWNrIGFuZCBEZWNrZXIsUmluZ2Nvbm4sQ01GLEV1ZnksU2Ftc3VuZyxNaWNyb3NvZnQsUmVNYXJrYWJsZSxBbGllbndhcmUsLCwNCjExLCwsQnJvb2tzLFRoZSBHeW0gUGVvcGxlLEJyb29rbHluIGJlZGRpbmcsTmVzcHJlc3NvLCwxTW9yZSxBcmxvLCxSYXplciwsQ29yc2FpciwsLA0KMTIsLCxDcm9jcywsRWlnaHQgU2xlZXAsQ3Vpc2luYXJ0LCxKQkwsLCwsLEhQLCwsDQpOb3RlcywsLCwsLCwsLCwsLCwsLCwNCiwsIlByaW9yaXRpc2UgYmlnZ2VzdCAlLyQgZGlzY291bnQsIFR2cyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiB0aGUgbW9zdCBwb3B1bGFyIGV2ZW4gaWYgdGhleSBhcmUgc3RpbGwgZXhwZW5zaXZlIiwiTm8gcGF0dGVybiB0byBwcmljaW5nL2Rpc2NvdW50LCByZWFkZXJzIG1haW5seSBzaG9wIGJ5IGJyYW5kL3JlY29nbmlzYWJsZSBzaG9lcyIsIk5vIHBhdHRlcm4gdG8gcHJpY2luZy9kaXNjb3VudCwgcmVhZGVycyBtYWlubHkgc2hvcCBieSBicmFuZCIsIkEgbGFiZWwgd2lsbCBkZWZpbml0ZWx5IGhlbHAgaGVyZSBlLmcuIGJlc3QgZm9yIHNpZGUgc2xlZXBlciwgYmVzdCBtZW1vcnkgZm9hbSIsIkFwcGxpYW5jZXMgaXMgYSBiaWcgY2F0ZWdvcnksIGlzIGl0IHBvc3NpYmxlIHRvIHNwbGl0IGludG8ga2l0Y2hlbiBhcHBsaWFuY2VzLCBmbG9vcmNhcmUsIGFpciBoZWFsdGgvY29vbGluZz8gT3Igc2ltaWxhciIsIkZvY3VzIG9uIHZhbHVlIGZvciBtb25leSwgR2FybWlucyB3aXRoIH41MCUgb2ZmIGhhdmUgYmVlbiBwb3B1bGFyIGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN0aWxsICQ1MDAiLCwsLCxJbmNsdWRlIEtpbmRsZXMsSSB3b3VsZCBpbmNsdWRlIHdpZmkgcm91dGVycyBoZXJlIGluc3RlYWQgb2Ygc21hcnQgaG9tZSxDYW4gd2Ugc3VyZmFjZSBwaG9uZSBwcm92aWRlciBkZWFscz8gVC1tb2JpbGUgYW5kIHZlcml6b24gd291bGQgbWFrZSBhIGxvdCBtb3JlIG1vbmV5IHRoYW4gQW1hem9uLCwNCiwsaGF2aW5nIGEgJ2Jlc3QgZm9yJyBsYWJlbCB3b3VsZCBiZSBoZWxwZnVsIGUuZy4gYmVzdCBmb3IgYnJpZ2h0IHJvb20sQ2FuIHdlIHN0b3Aga2lkcyBzaG9lcyBmcm9tIHB1bGxpbmcgdGhyb3VnaD8sIldpbGwgdGhpcyBpbmNsdWRlIGFjY2Vzc29yaWVzIGUuZy4gY2FwcywgYmFncywgaWYgc28gbWFrZSBzdXJlIHRoZXNlIGFyZSBtaXhlZCB0aHJvdWdob3V0IGNsb3RoaW5nIGRlYWxzIixXaWxsIHRoaXMgaW5jbHVkZSB0b3BwZXJzIGFuZCBwaWxsb3dzPyBTZWVpbmcgbW9yZSBtb21lbnR1bSB3aXRoIHRoaXMgY2F0ZWdvcnkgcmVjZW50bHkgc28gYSBiZWRkaW5nIHRhYiBtaWdodCB3b3JrLCwiTmVlZCB0byBtYWtlIHN1cmUgYmFuZHMsIHNjcmVlbiBwcm90ZWN0b3JzIGV0Yy4gZG9uJ3QgcHVsbCBpbnRvIGhlcmUiLCwsLCwsLCwsDQosLCJQcmlvcml0aXNlIDY1JycgYW5kIDU1JyBpbmNoIFRWcywgdGhlbiBiaWdnZXIgc2NyZWVucyBiZWZvcmUgdGhlIHNtYWxsZXIgc2l6ZXMiLCwsUXVlZW4gaXMgdGhlIG1vc3QgcG9wdWxhciBzaXplIGluIHRoZSBVUyAtIHByaW9yaXRpc2UgZGVhbHMgZm9yIHRoaXMgc2l6ZSwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpDYXRlZ29yaWVzIHRvIGNvbnNpZGVyLCxQcm9kdWN0cyBpbmNsdWRlZCwsLCwsLCwsLCwsLCwsDQpVbmRlciAkNTA/LCxBaXIgdGFncywsLCwsLCwsLCwsLCwsDQosLFBvcnRhYmxlIGNoYXJnZXJzL3dpcmVsZXNzIGNoYXJnZXJzLCwsLCwsLCwsLCwsLCwNCiwsIldhdGVyIGJvdHRsZXMgKHN0YW5sZXlzLCBPd2FsYSwgSHlkcm8gZmxhc2ssIFlldGkpIiwsLCwsLCwsLCwsLCwsDQosLEhhbmQgaGVsZCBmYW5zLCwsLCwsLCwsLCwsLCwNCiwsLCwsLCwsLCwsLCwsLCwNCmhvbWUgb2ZmaWNlLCxvZmZpY2UgY2hhaXJzLCwsLCwsLCwsLCwsLCwNCiwsc3RhbmRpbmcgZGVza3MsLCwsLCwsLCwsLCwsLA0KLCxtb25pdG9ycywsLCwsLCwsLCwsLCwsDQosLEtleWJvYXJkcywsLCwsLCwsLCwsLCwsDQosLGRvY2tpbmcgc3RhdGlvbiwsLCwsLCwsLCwsLCwsDQosLCwsLCwsLCwsLCwsLCwsDQpHYW1pbmcsLENvbnNvbGVzLCwsLCwsLCwsLCwsLCwNCiwsQWNjZXNzb3JpZXMsLCwsLCwsLCwsLCwsLA0KLCxHYW1lcywsLCwsLCwsLCwsLCwsDQosLENvdWxkIGluY2x1ZGUgTGVnbz8sLCwsLCwsLCwsLCwsLA==")));              const text = preloadedCSV;              const parsed = parseCSV(text);                            const rowsByName = {};              let filterStart = -1;              parsed.forEach((rc, i) => {                 if (rc && rc.length > 0 && rc[0]) rowsByName[rc[0]] = rc;                 if (rc && rc.length > 0 && rc[0] === 'Filter buttons') filterStart = i;              });                            const cols = [];              if(rowsByName['Roundel text']) {                const headerRow = rowsByName['Roundel text'];                for(let col = 1; col < headerRow.length; col++) {                   let label = headerRow[col];                   if (!label) continue;                                      let q = rowsByName['Search Query'] && rowsByName['Search Query'][col] ? rowsByName['Search Query'][col] : '';                   let img = rowsByName['Roundel image'] && rowsByName['Roundel image'][col] ? rowsByName['Roundel image'][col] : '';                   let ds = rowsByName['Discount Amount'] && rowsByName['Discount Amount'][col] ? rowsByName['Discount Amount'][col] : '';                   let pr = rowsByName['Price Range'] && rowsByName['Price Range'][col] ? rowsByName['Price Range'][col] : '';                   let rt = rowsByName['Retailer'] && rowsByName['Retailer'][col] ? rowsByName['Retailer'][col] : '';                   let ot = rowsByName['Offer Type'] && rowsByName['Offer Type'][col] ? rowsByName['Offer Type'][col] : '';                                      let filters = [];                   if(filterStart > 0) {                     for(let r = filterStart + 1; r < parsed.length; r++) {                         if(!parsed[r] || parsed[r][0] === 'Notes' || parsed[r][0] === 'Categories to consider') break;                         let f = parsed[r][col];                         if(f) filters.push(f);                     }                   }                   cols.push({ label, img, q, ds, pr, rt, ot, filters });                }              }              this.carouselData = cols;              if (this.carouselData && this.carouselData.length > 0) {                 const isMatched = this.carouselData.some(c => c.q === this.currentQuery || c.label === this.currentQuery);                 if (!isMatched) {                    const first = this.carouselData[0];                    this.currentQuery = first.q || first.label;                    if (this.priceFilter) this.priceFilter.value = 'all';                    if (this.customPriceMin) this.customPriceMin.value = '';                    if (this.customPriceMax) this.customPriceMax.value = '';                    let dPr = first.pr || 'all';                    if (typeof dPr === 'string' && dPr !== 'all') {                       let prLower = dPr.toLowerCase();                       if (prLower.includes('min') || prLower.includes('over')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else if (prLower.includes('max') || prLower.includes('under')) {                          let m = dPr.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       }                    }                    let dAm = '0';                    if(first.ds && typeof first.ds === 'string') {                       let m = first.ds.match(/(\d+)/);                       if(m) dAm = m[1];                    }                    if (this.discountFilter) this.discountFilter.value = dAm;                    if (this.offerTypeSelect) this.offerTypeSelect.value = first.ot || '';                    if (this.retailerSelect) this.retailerSelect.value = first.rt || '';                    this.selectedBrands = [];                    if (this.brandDropdown) {                        const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                        chks.forEach(chk => chk.checked = false);                    }                    if (this.searchInput) this.searchInput.value = this.currentQuery;                 }              }              this.renderCarouselUI();          } catch(e){ console.warn(e); }        }                renderCarouselUI() {           const roundelWrapper = this.root.querySelector('.tg-df-carousel-roundels');           if(!roundelWrapper || !this.carouselData) return;                      let html = '';           this.carouselData.forEach(r => {              const q = r.q || r.label;              const isActive = (this.currentQuery === q || this.currentQuery === r.label) ? 'active' : '';              const imgHtml = r.img ? `\x3Cimg src="${r.img}" alt="${r.label}" />` : `\x3Csvg width="32" height="32" fill="#1F69FF" viewBox="0 0 24 24">\x3Cpath d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>\x3C/svg>`;              html += `                \x3Cdiv class="tg-df-roundel tg-df-carousel-cat ${isActive}" data-label="${this.escapeHTML(r.label)}">                  \x3Cdiv class="tg-df-roundel-img-box">${imgHtml}\x3C/div>                  \x3Cspan class="tg-df-roundel-label">${this.escapeHTML(r.label)}\x3C/span>                \x3C/div>              `;           });           roundelWrapper.innerHTML = html;                      // Rebind clicks           const roundels = this.root.querySelectorAll('.tg-df-carousel-cat');           roundels.forEach(rNode => {             rNode.addEventListener('click', () => {                const r = this.carouselData.find(c => c.label === rNode.getAttribute('data-label'));                 if(!r) return;                                  if (typeof trackHawkEvent !== 'undefined') {                     trackHawkEvent({                         clickType: "CC",                         widgetId: this.widgetId,                         productCategoryName: "deals",                         zeroBasedProductIndexOrNull: null,                         totalDealsOrProducts: null,                         areaClicked: "Category Roundel",                         revenueId: this.revenueId,                         isoCurrencyCode: typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD',                         queryName: r.label,                         widgetTypeName: this.widgetTypeName                     });                 }                this.currentQuery = r.q || r.label;                const labelTitle = this.root.querySelector('#tg-df-carousel-title-label');                if (labelTitle) labelTitle.textContent = 'Best ' + this.currentQuery;                if (this.priceFilter) this.priceFilter.value = 'all';                if (this.customPriceMin) this.customPriceMin.value = '';                if (this.customPriceMax) this.customPriceMax.value = '';                let dPr = r.pr || 'all';                if (typeof dPr === 'string' && dPr !== 'all') {                   let prLower = dPr.toLowerCase();                   if (prLower.includes('min') || prLower.includes('over')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMin) this.customPriceMin.value = m[1];                   } else if (prLower.includes('max') || prLower.includes('under')) {                      let m = dPr.match(/(\d+)/);                      if (m && this.customPriceMax) this.customPriceMax.value = m[1];                   }                }                                let discountAmount = '0';                if(r.ds && typeof r.ds === 'string') {                   let m = r.ds.match(/(\d+)/);                   if(m) discountAmount = m[1];                }                if (this.discountFilter) this.discountFilter.value = discountAmount;                if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                                // Clear brands                    this.selectedBrands = [];                    if (this.brandDropdown) {                    const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                    chks.forEach(chk => chk.checked = false);                }                                if (this.searchInput) this.searchInput.value = this.currentQuery;                                roundels.forEach(ro => ro.classList.remove('active'));                if (rNode) rNode.classList.add('active');                                this.renderCarouselFilters(r);                this.fetchDeals(this.currentQuery);             });           });                      // Auto-highlight active           const activeR = this.carouselData.find(c => c.q === this.currentQuery || c.label === this.currentQuery);           if(activeR) this.renderCarouselFilters(activeR);        }                renderCarouselFilters(r) {           const filtersWrap = this.root.querySelector('.tg-df-carousel-filters-wrap');           if(!filtersWrap) return;                      let html = `\x3Cbutton class="tg-df-carousel-filter-btn" data-type="all">All\x3C/button>`;                      r.filters.forEach(f => {              let fL = f.toLowerCase();              let icon = '';              let logic = `data-type="custom" data-v="${this.escapeHTML(f)}"`;              if (fL === 'amazon deals' || fL === 'prime deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/fwoVXvL79turN3Ph535m38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/u75QjVpt3w2EsMimJiRo38-600-100.png" class="active-img" alt="" /> Prime deals\x3C/button>`;              } else if (fL === 'lightning deals') {                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>\x3Cimg src="https://cdn.mos.cms.futurecdn.net/HqAui7w97ft2NPqBtQ5r38-600-100.png" class="inactive-img" alt="" />\x3Cimg src="https://cdn.mos.cms.futurecdn.net/yWPQ5yyQRhUwVKzGwYbh38-600-100.png" class="active-img" alt="" /> Lightning deals\x3C/button>`;              } else {                 if (fL.includes('lightning')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zap">\x3Cpolygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2">\x3C/polygon>\x3C/svg>`;                 } else if (fL.includes('% off')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-tag">\x3Cpath d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z">\x3C/path>\x3Ccircle cx="7.5" cy="7.5" r=".5" fill="currentColor">\x3C/circle>\x3C/svg>`;                 } else if (fL.includes('under') || fL.includes('min ')) {                    icon = `\x3Csvg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge-dollar-sign">\x3Cpath d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z">\x3C/path>\x3Cpath d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8">\x3C/path>\x3Cpath d="M12 18V6">\x3C/path>\x3C/svg>`;                 }                 html += `\x3Cbutton class="tg-df-carousel-filter-btn" ${logic}>${icon} ${this.escapeHTML(f)}\x3C/button>`;              }           });                      filtersWrap.innerHTML = html;                      const btns = filtersWrap.querySelectorAll('button');           btns.forEach(b => {             b.addEventListener('click', () => {                const type = b.getAttribute('data-type');                if (type === 'custom') {                   const v = b.getAttribute('data-v');                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: `filter-custom-${(v||'').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, name: 'Custom Filter', label: v });                }                if (type === 'all') {                   if (typeof trackElementInteraction === 'function') trackElementInteraction({ id: 'filter-clear-all', name: 'Clear all', label: 'Clear all filters' });                   // reset everything                   btns.forEach(btn => btn.classList.remove('active'));                   b.classList.add('active');                                      // Reset prices                   if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   if (this.brandDropdown) {                     const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                     chks.forEach(chk => chk.checked = false);                   }                } else {                   const v = b.getAttribute('data-v');                   const fL = v.toLowerCase();                                      let mapRet = ['amazon', 'walmart', 'best buy', 'target', 'john lewis', 'currys', 'argos'];                   const getCategory = (s) => {                      if (s === 'lightning deals' || s === 'amazon deals' || s === 'prime deals') return 'offer';                      if (s.includes('% off')) return 'discount';                      if (s.includes('under') || s.includes('over') || s.includes('min') || s.includes('max')) return 'price';                      if (mapRet.includes(s)) return 'retailer';                      return 'brand';                   };                   const cat = getCategory(fL);                   const wasActive = b.classList.contains('active');                   if (cat !== 'brand') {                      btns.forEach(btn => {                          if (btn === b) return;                          if (btn.getAttribute('data-type') === 'all') return;                          const bV = btn.getAttribute('data-v');                          if (!bV) return;                          if (getCategory(bV.toLowerCase()) === cat) btn.classList.remove('active');                      });                   }                   if (wasActive) b.classList.remove('active');                   else b.classList.add('active');                   let anyActive = Array.from(btns).some(btn => btn !== btns[0] && btn.classList.contains('active'));                   if (!anyActive) {                       btns[0].click();                       return;                   } else {                       btns[0].classList.remove('active');                   }                                      if (this.priceFilter) this.priceFilter.value = 'all';                   if (this.customPriceMin) this.customPriceMin.value = '';                   if (this.customPriceMax) this.customPriceMax.value = '';                   let dPr = r.pr || 'all';                   if (typeof dPr === 'string' && dPr !== 'all') {                      let prLower = dPr.toLowerCase();                      if (prLower.includes('min') || prLower.includes('over')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMin) this.customPriceMin.value = m[1];                      } else if (prLower.includes('max') || prLower.includes('under')) {                         let m = dPr.match(/(\d+)/);                         if (m && this.customPriceMax) this.customPriceMax.value = m[1];                      }                   }                                      let discountAmount = '0';                   if(r.ds && typeof r.ds === 'string') {                      let m = r.ds.match(/(\d+)/);                      if(m) discountAmount = m[1];                   }                   if (this.discountFilter) this.discountFilter.value = discountAmount;                   if (this.offerTypeSelect) this.offerTypeSelect.value = r.ot || '';                   if (this.retailerSelect) this.retailerSelect.value = r.rt || '';                   this.selectedBrands = [];                   btns.forEach(btn => {                       if (!btn.classList.contains('active') || btn.getAttribute('data-type') === 'all') return;                       const vv = btn.getAttribute('data-v');                       const vl = vv.toLowerCase();                                              if (vl === 'lightning deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_lightning';                       } else if (vl === 'amazon deals' || vl === 'prime deals') {                          if (this.offerTypeSelect) this.offerTypeSelect.value = 'amazon_prime';                       } else if (vl.includes('% off')) {                          let m = vl.match(/(\d+)%/);                          if (m && this.discountFilter) this.discountFilter.value = m[1];                       } else if (vl.includes('under') || vl.includes('max')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMax) this.customPriceMax.value = m[1];                       } else if (vl.includes('min') || vl.includes('over')) {                          let m = vl.match(/(\d+)/);                          if (m && this.customPriceMin) this.customPriceMin.value = m[1];                       } else {                          let foundR = mapRet.find(x => x === vl);                          if (foundR) {                             let realR = ['Amazon', 'Walmart', 'Best Buy', 'Target', 'John Lewis', 'Currys', 'Argos'].find(x => x.toLowerCase() === vl);                             if (this.retailerSelect) this.retailerSelect.value = realR;                          } else {                             this.selectedBrands.push(vv);                          }                       }                   });                                      if (this.brandDropdown) {                       const chks = this.brandDropdown.querySelectorAll('.tg-df-brand-chk');                       chks.forEach(c => c.checked = this.selectedBrands.includes(c.value));                   }                                      if (r.pr && typeof r.pr === 'string') {                       let prL = r.pr.toLowerCase();                       if (prL.includes('under $')) {                           let m = prL.match(/under \$(\d+)/i);                           if (m && this.customPriceMax && !this.customPriceMax.value) this.customPriceMax.value = m[1];                       }                   }                }                                this.fetchDeals(this.currentQuery);             });           });                      // default to highlighting first           btns[0].classList.add('active');        }async fetchDeals(query, append = false) {          if (!append) {             this.showLoading();             this.deals = [];             this.displayLimit = (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          } else {             this.displayLimit += (this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12;          }                    try {            if (this.getViewMode() === 'savings_squad') {               await this.fetchSavingsSquad(append);            } else {               if (this.isBroadQuery(query)) {                 await this.fetchAdviserDeals(query, append);               } else {                 await this.fetchHawkDeals(query, append);                 if (this.deals.length === 0) {                   await this.fetchAdviserDeals(query, append);                 }               }            }          } catch (error) {            console.warn("[Tom's Guide Widget] Fetch error:", error);            this.showError();          }        }        async fetchSavingsSquad() {          let topArticles = this.airedaleArticles;          if (!topArticles) {            const airedaleUrl = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`;            let res;            try {               res = await fetch(airedaleUrl);            } catch(e) {               try { res = await fetch(`https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50`); } catch (err) { console.warn("Fallback fetch failed", err); return; }            }            if (!res.ok) throw new Error('Airedale API Error');            const articles = await res.json();            topArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);            this.airedaleArticles = topArticles;                        let tagCounts = {};            topArticles.forEach((a) => {              let articleTags = new Set();              if (a.articlecategory && Array.isArray(a.articlecategory)) {                 a.articlecategory.forEach((t) => articleTags.add(t));              }              articleTags.forEach(t => {                 tagCounts[t] = (tagCounts[t] || 0) + 1;              });            });                        this.airedaleTags = Object.keys(tagCounts).sort((a, b) => tagCounts[b] - tagCounts[a]);            this.airedaleTagCounts = tagCounts;          }                    let targetArticles = topArticles;          if (this.activeDealTag) {             const cleanTag = this.activeDealTag.toLowerCase().replace(/&/g, '').replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');             const encodedTag = encodeURIComponent(cleanTag);             const url = `https://airedale.futurecdn.net/feeds/feed_1776420579726.json?site=tomsguide&articleType=deals&limit=50&articleCategoryHandle=${encodedTag}`;             try {                const res = await fetch(url);                if (res.ok) {                   const articles = await res.json();                   targetArticles = Array.isArray(articles) ? articles.slice(0, 50) : ((articles.data && Array.isArray(articles.data)) ? articles.data.slice(0, 50) : []);                }             } catch(e) {                console.warn("Failed to fetch by activeDealTag", e);             }          }          let extractedDeals = [];          let dynamicBrandsCounts = {};                    targetArticles.forEach((article) => {             if (!article.articlepage) return;                          let pageData = [];             try {                pageData = JSON.parse(article.articlepage[0]);             } catch(e){ console.warn(e); }                          const savingsSquad = pageData.filter((p) => p.type === 'deal' || p.type === 'featured-product');                          savingsSquad.forEach((block, idx) => {                const data = block.data || {};                const isFeatured = block.type === 'featured-product';                                const link = data.link || {};                const priceObj = data.price || {};                const image = data.image || {};                                if (data.brand) {                   data.brand = data.brand.replace(/^\d+\.\s*/, '').trim();                   dynamicBrandsCounts[data.brand] = (dynamicBrandsCounts[data.brand] || 0) + 1;                }                const externalUrl = isFeatured ? data.url : (link.href || null);                let summaryTitle = isFeatured ? (data.name || data.brand) : (data.productName || link.label || article.articlename);                let description = isFeatured ? (data.strapline || '') : (data.text || '');                                if (!isFeatured && !data.productName && data.text) {                   const brSplit = data.text.split(new RegExp('\x3Cbr\\s*\\/?\\x3E', 'i'));                   if (brSplit.length > 1) {                     summaryTitle = brSplit[0].replace(/<[^>]+>/g, '').trim();                     description = brSplit.slice(1).join(' ').replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();                   } else {                     const match = data.text.match(/\x3Cstrong>(.*?)<\/strong>/);                     if (match) {                       summaryTitle = match[1].replace(/<[^>]+>/g, '').trim();                       if (summaryTitle.endsWith(':')) summaryTitle = summaryTitle.slice(0, -1);                     }                   }                }                                let imageUrl = isFeatured ? image.mos : (image.src || null);                if (imageUrl && imageUrl.startsWith('//')) imageUrl = 'https:' + imageUrl;                                description = description.replace(/<br\s*\/?>/gi, ' ').replace(/<\/?(p|div)[^>]*>/gi, ' ').replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').replace(/View Deal$/i, '').trim();                                let merchantName = data.retailer || '';                if (!merchantName && externalUrl) {                   try {                     merchantName = new URL(externalUrl).hostname.replace('www.', '').split('.')[0];                     merchantName = merchantName.charAt(0).toUpperCase() + merchantName.slice(1);                   }catch(e){ console.warn(e); }                }                if (!merchantName) merchantName = 'Retailer';                const q = (this.currentQuery || '').toLowerCase();                const activeTagLogic = (this.activeDealTag || '').toLowerCase();                if (q.length > 2 && q !== activeTagLogic) {                   const searchTarget = `${summaryTitle || ''} ${description || ''}`.toLowerCase();                   if (!searchTarget.includes(q)) return;                }                let rawPrice = 0;                let rawMsrp = 0;                let currencyStr = '$';                if (isFeatured) {                   rawPrice = typeof data.salePrice === 'number' && data.salePrice > 0 ? data.salePrice : (typeof data.price === 'number' ? data.price : 0);                   rawMsrp = typeof data.salePrice === 'number' && typeof data.price === 'number' && data.price > data.salePrice ? data.price : 0;                   currencyStr = data.currency === 'GBP' ? '£' : '$';                } else {                   rawPrice = priceObj.amount ? parseFloat(priceObj.amount) : 0;                   rawMsrp = priceObj.amountWas ? parseFloat(priceObj.amountWas) : 0;                   currencyStr = priceObj.currency === 'GBP' ? '£' : '$';                }                                let savingAmt = 0;                let savingLabel = '';                if (rawPrice > 0 && rawMsrp > rawPrice) {                   savingAmt = parseFloat((rawMsrp - rawPrice).toFixed(2));                   savingLabel = `Save ${currencyStr}${savingAmt}`;                }                                // Apply Brand filter                if (this.selectedBrands && this.selectedBrands.length > 0) {                   const itemBrand = (data.brand || '').toLowerCase();                   const hasMatch = this.selectedBrands.some(sb => sb.toLowerCase() === itemBrand);                   if (!hasMatch) return;                }                // Apply Price filter                let priceFilterVal = null;                const min = this.customPriceMin ? this.customPriceMin.value : '';                const max = this.customPriceMax ? this.customPriceMax.value : '';                if (min || max) {                   priceFilterVal = `${min}_${max}`;                } else if (this.priceFilter && this.priceFilter.value !== 'all') {                   priceFilterVal = this.priceFilter.value;                }                if (priceFilterVal && rawPrice > 0) {                   if (priceFilterVal === 'under50' && rawPrice >= 50) return;                   if (priceFilterVal === 'over50' && rawPrice <= 50) return;                   if (priceFilterVal === 'over30' && rawPrice <= 30) return;                   if (priceFilterVal === 'over500' && rawPrice <= 500) return;                   if (priceFilterVal.includes('_')) {                      const parts = priceFilterVal.split('_');                      const min = parseFloat(parts[0]);                      const max = parseFloat(parts[1]);                      if (!isNaN(min) && rawPrice < min) return;                      if (!isNaN(max) && rawPrice > max) return;                   }                }                // Apply Discount filter                if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {                   const requiredDiscount = parseInt(this.discountFilter.value);                   if (!isNaN(requiredDiscount) && requiredDiscount > 0) {                      if (!rawMsrp || rawMsrp <= rawPrice) return;                      const ratio = Math.round((1 - (rawPrice / rawMsrp)) * 100);                      if (ratio < requiredDiscount) return;                   }                }                                extractedDeals.push({                   id: `airedale-${article.id || Math.random()}-${idx}`,                   url: externalUrl,                   image: imageUrl,                   fallbackImage: imageUrl,                   title: summaryTitle,                   brand: data.brand || '',                   productName: data.productName || '',                   merchant: merchantName,                   rawPrice: rawPrice,                   rawMsrp: rawMsrp,                   price: rawPrice > 0 ? rawPrice.toString() : '',                   msrp: rawMsrp > 0 ? rawMsrp.toString() : '',                   currency: currencyStr,                   isCheckPrice: !rawPrice,                   savingLabel: savingLabel,                   savingType: rawMsrp > rawPrice ? 'amount' : 'none',                   isPrime: false,                   starRating: null,                   description: description,                   text: data.text || ''                });             });          });                    const airedaleBrandsList = Object.keys(dynamicBrandsCounts).map(b => ({              formatted_value: b,              count: dynamicBrandsCounts[b]          })).sort((a,b) => b.count - a.count);                    if (this.getViewMode() === 'savings_squad') {             this.populateBrandDropdown(airedaleBrandsList.slice(0, 15));             if (this.brandFilterWrapper) {                if (airedaleBrandsList.length === 0) {                    this.brandFilterWrapper.style.display = 'none';                } else {                    this.brandFilterWrapper.style.display = 'flex';                }             }          }                    this.deals = extractedDeals;          this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        isBroadQuery(query) {          const q = query.toLowerCase();          const intentModifiers = ['deals', 'best', 'sale', 'under', 'cheap', 'offers', 'discount'];          return intentModifiers.some(term => q.includes(term));        }        async fetchHawkDeals(query, append = false) {          const url = new URL(this.apiUrl);          url.searchParams.append('model_name', query);          const areaCode = this.getAreaCode();          if (areaCode) {            url.searchParams.append('area', areaCode);          }                    if (append && this.deals.length > 0) {            url.searchParams.append('offset', this.deals.length.toString());          }                    if (this.retailerSelect && this.retailerSelect.value) {            url.searchParams.append('filter_merchant_name', this.retailerSelect.value);          }                    if (this.selectedBrands && this.selectedBrands.length > 0) {            url.searchParams.append('filter_label[text_brand]', this.selectedBrands.join(','));          }                    let priceVal = null;          const min = this.customPriceMin ? this.customPriceMin.value : '';          const max = this.customPriceMax ? this.customPriceMax.value : '';          if (min || max) {             priceVal = `${min}_${max}`;          } else if (this.priceFilter && this.priceFilter.value !== 'all') {             priceVal = this.priceFilter.value;          }          if (priceVal) {            if (priceVal === 'under50') {              url.searchParams.append('filter_max_price', '50');            } else if (priceVal === 'over50') {              url.searchParams.append('filter_min_price', '50');            } else if (priceVal === 'over30') {              url.searchParams.append('filter_min_price', '30');            } else if (priceVal === 'over500') {              url.searchParams.append('filter_min_price', '500');            } else if (priceVal.includes('_')) {              const parts = priceVal.split('_');              if (parts[0]) url.searchParams.append('filter_min_price', parts[0]);              if (parts[1]) url.searchParams.append('filter_max_price', parts[1]);            }          }                    if (this.discountFilter && this.discountFilter.value !== 'all' && this.discountFilter.value !== '0') {            const v = parseInt(this.discountFilter.value);            if (!isNaN(v) && v > 0) {              const ratio = (100 - v) / 100;              url.searchParams.append('min_discount_ratio', ratio.toString());            }          }                    if (this.offerTypeSelect && this.offerTypeSelect.value) {            url.searchParams.append('offer', this.offerTypeSelect.value);          }                    url.searchParams.append('filter_product_types', 'deals');                    if (this.rowsSelect && this.rowsSelect.value) {            url.searchParams.append('rows', this.rowsSelect.value);          } else {             url.searchParams.append('rows', '12'); // default          }          let response;          try {             response = await fetch(url.toString());          } catch(e) {             if (window.location.protocol === 'file:') {                console.warn("[Tom's Guide Widget] fetch from file:// blocked by local CORS policy, falling back to Adviser mock.");                await this.fetchAdviserDeals(query);                return;             }             console.warn("Hawk fetch failed", e);             this.deals = [];             this.render();             return;          }          if (!response.ok) {            throw new Error('Hawk API Response Error');          }          const rawData = await response.json();          // Safely locate data array from potentially wrapped response          let offers = [];          let modelInfoArray = [];                    let brandFilterData = null;          if (rawData && rawData.widget && rawData.widget.data && Array.isArray(rawData.widget.data.filters)) {             brandFilterData = rawData.widget.data.filters.find(f => f.type === 'label_text_brand');          } else if (rawData && rawData.data && Array.isArray(rawData.data.filters)) {             brandFilterData = rawData.data.filters.find(f => f.type === 'label_text_brand');          }          if (brandFilterData && Array.isArray(brandFilterData.values) && brandFilterData.values.length > 0) {             this.populateBrandDropdown(brandFilterData.values);          } else {             if (this.brandFilterWrapper && this.selectedBrands.length === 0) {                this.brandFilterWrapper.style.display = 'none';             }          }                    if (rawData && rawData.widget && rawData.widget.data) {            if (Array.isArray(rawData.widget.data.offers)) offers = rawData.widget.data.offers;            if (rawData.widget.data.model_info && typeof rawData.widget.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.widget.data.model_info) ? rawData.widget.data.model_info : Object.values(rawData.widget.data.model_info);            }          } else if (rawData && rawData.data) {            if (Array.isArray(rawData.data.offers)) offers = rawData.data.offers;            if (rawData.data.model_info && typeof rawData.data.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.data.model_info) ? rawData.data.model_info : Object.values(rawData.data.model_info);            }          } else {            if (Array.isArray(rawData)) offers = rawData;            else if (rawData && Array.isArray(rawData.offers)) offers = rawData.offers;            else if (rawData && rawData.offers && Array.isArray(rawData.offers.offer)) offers = rawData.offers.offer;            else if (rawData && rawData.offers) offers = [].concat(rawData.offers);                        if (rawData && rawData.model_info && typeof rawData.model_info === 'object') {              modelInfoArray = Array.isArray(rawData.model_info) ? rawData.model_info : Object.values(rawData.model_info);            }          }          let modelDetails = {};          modelInfoArray.forEach(m => {            const mId = m.model_id || m.id;            if (mId) {              modelDetails[mId] = {                score: m.score != null ? parseFloat(m.score) : null,                brand: m.brand || null,                parent: (m.parents && Array.isArray(m.parents) && m.parents.length > 0) ? m.parents[0].name : null              };            }          });          offers.forEach(item => {            let data = { ...item };            const mId = data.model_id;            if (mId && modelDetails[mId]) {              data.review_score = modelDetails[mId].score;              data.model_brand = modelDetails[mId].brand;              data.model_parent = modelDetails[mId].parent;            } else {              data.review_score = null;            }                        let itemOffers = [];            if (Array.isArray(item.offers)) itemOffers = item.offers;            else if (Array.isArray(item.offer)) itemOffers = item.offer;            else if (item.offers && typeof item.offers === 'object') itemOffers = [item.offers];            else if (item.offer && typeof item.offer === 'object') itemOffers = [item.offer];            if (itemOffers.length > 0) {              itemOffers.forEach(subItem => {                let subData = { ...item, ...subItem };                const subId = subData.model_id;                if (subId && modelDetails[subId]) {                  subData.review_score = modelDetails[subId].score;                  subData.model_brand = modelDetails[subId].brand;                  subData.model_parent = modelDetails[subId].parent;                } else if (data.review_score != null) {                  subData.review_score = data.review_score;                }                if (subData.merchant && typeof subData.merchant === 'object') {                  subData.merchant_name = subData.merchant.name;                }                this.deals.push(this.extractDealData(subData));              });              return;            }                        if (item.merchant && typeof item.merchant === 'object') {              data.merchant_name = item.merchant.name;            }                        this.deals.push(this.extractDealData(data));          });                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        async fetchAdviserDeals(query) {          // ======================================================================          // TODO: ADVISER API REPLACEMENT          // The code below simulates the Adviser API response using mock data.          // Once the real endpoint is ready, remove getAdviserMockData() and           // perform an actual fetch() request similar to fetchHawkDeals().          // Example:          // const area = this.getAreaCode();          // let apiUrl = `https://your-adviser-api.com/search?q=${query}&area=${area}`;          // if (this.priceFilter && this.priceFilter.value !== 'all') {          //   const val = this.priceFilter.value;          //   if (val === 'under50') apiUrl += '&filter_max_price=50';          //   else if (val === '50_100') apiUrl += '&filter_max_price=100';          //   else if (val === '100_200') apiUrl += '&filter_max_price=200';          //   else if (val === '200_500') apiUrl += '&filter_max_price=500';          // }          // const res = await fetch(apiUrl);          // const rawData = await res.json();          // ======================================================================          // Simulating network latency          await new Promise(resolve => setTimeout(resolve, 400));                    const rawData = this.getAdviserMockData();          let offers = [];                    if (rawData && rawData.data && rawData.data.Get && Array.isArray(rawData.data.Get.Deal)) {            offers = rawData.data.Get.Deal;          }                    // Basic client-side filtering for the mock if we want it to react to the query          const q = query.toLowerCase();          const selectedRetailer = (this.retailerSelect && this.retailerSelect.value) ? this.retailerSelect.value.toLowerCase() : null;                    offers.forEach(item => {            const dataObj = item;                        // Apply retailer filter            const itemRetailer = (dataObj.dataRetailer || '').toLowerCase();            if (selectedRetailer && itemRetailer !== selectedRetailer && !itemRetailer.includes(selectedRetailer)) {              return;            }                        // Apply mock price filter            let price = dataObj.dataDiscountedPrice || 0;            if (typeof price === 'string') {              price = parseFloat(price.replace(/[^0-9.]/g, ''));            }            let priceVal = null;            const min = this.customPriceMin ? this.customPriceMin.value : '';            const max = this.customPriceMax ? this.customPriceMax.value : '';            if (min || max) {               priceVal = `${min}_${max}`;            } else if (this.priceFilter && this.priceFilter.value !== 'all') {               priceVal = this.priceFilter.value;            }            if (priceVal) {              if (priceVal === 'under50' && price >= 50) return;              if (priceVal === 'over50' && price <= 50) return;              if (priceVal === 'over30' && price <= 30) return;              if (priceVal === 'over500' && price <= 500) return;              if (priceVal.includes('_')) {                 const parts = priceVal.split('_');                 if (parts[0] && price < parseFloat(parts[0])) return;                 if (parts[1] && price > parseFloat(parts[1])) return;              }            }                        // Map Adviser schema to our widget's expected schema            const mappedData = {              url: dataObj.linkHREF || dataObj.dataLink || '#',              image: dataObj.imageURL || (dataObj.image && dataObj.image.src) || '',              title: dataObj.dataProduct || (dataObj.product && dataObj.product.name) || 'Product Deal',              merchant: dataObj.dataRetailer || 'Retailer',              price: dataObj.dataDiscountedPrice || 0,              currency: dataObj.dataCurrency === 'USD' ? '$' : (dataObj.dataCurrency || '$'),              msrp: dataObj.dataOriginalPrice || null            };                        const titleLow = mappedData.title.toLowerCase();            const merchLow = mappedData.merchant.toLowerCase();                        // Smarter mock filtering            let isMatch = false;            if (q === '' || this.isBroadQuery(q)) {              isMatch = true;            } else if (titleLow.includes(q) || merchLow.includes(q)) {              isMatch = true;            } else if ((q.includes('laptop') || q.includes('mac') || q.includes('pc')) && (titleLow.includes('macbook') || titleLow.includes('laptop'))) {              isMatch = true;            } else if ((q.includes('tv') || q.includes('television')) && (titleLow.includes('tv') || titleLow.includes('oled') || titleLow.includes('qled'))) {              isMatch = true;            } else if ((q.includes('phone') || q.includes('smartphone')) && (titleLow.includes('galaxy') || titleLow.includes('phone'))) {              isMatch = true;            } else if ((q.match(/watch|fitness|run|shoe/)) && (titleLow.includes('forerunner') || titleLow.includes('saucony') || titleLow.includes('watch'))) {              isMatch = true;            }                        if (isMatch) {               this.deals.push(this.extractDealData(mappedData));            }          });                    let rowLimit = 12;          if (this.rowsSelect && this.rowsSelect.value) {            rowLimit = parseInt(this.rowsSelect.value, 10) || 12;          }          // Intentionally omitting the slice here to allow "Load More" to work if the API returns more                    this.sortData();          this.render();          if (typeof trackDealsAppeared !== 'undefined') {             trackDealsAppeared(this.widgetId, this.deals, this.revenueId, typeof this.getAreaCode === 'function' ? (this.getAreaCode() === 'GB' ? 'GBP' : 'USD') : 'USD', this.currentQuery, this.widgetTypeName);          }        }        getAdviserMockData() {          return {            "data": {              "Get": {                "Deal": [                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 300,                    "dataOriginalPrice": 399,                    "dataProduct": "Samsung Galaxy A36",                    "dataRetailer": "Samsung",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/MqDYsukV3JBG54te6dEs7j.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 14,                    "dataOriginalPrice": 24,                    "dataProduct": "Blink Mini",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/3JurmAjHsDa5tPdaHAwEV8.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 59,                    "dataOriginalPrice": 99,                    "dataProduct": "Ring Video Doorbell",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/rAh4uR7AsAsALCCLTXnLNJ.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 10,                    "dataOriginalPrice": 599,                    "dataProduct": "MacBook Neo",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/Lg4Dvg68j9SbB5CPNrTEpH.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 749,                    "dataOriginalPrice": 849,                    "dataProduct": "65\\\" Fire TV Omni 4K QLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/SG34ZWodUkLTxJvMTbjPYR.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 71,                    "dataOriginalPrice": 160,                    "dataProduct": "Saucony Hurricane 24",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/vxf7UD5T2Am7guVzFoFcZ4.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 649,                    "dataOriginalPrice": 749,                    "dataProduct": "Garmin Forerunner 970",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/3GKnEu7CdhtxPMfnPCMCiA.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1049,                    "dataOriginalPrice": 1499,                    "dataProduct": "LG 48\\\" C4 4K OLED TV",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/imvwZV9zoMD6fn9Afuge35.jpg"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 1499,                    "dataOriginalPrice": 2199,                    "dataProduct": "Samsung 49\\\" Odyssey Neo G9 4K Gaming Monitor",                    "dataRetailer": "Amazon",                    "imageURL": "http://cdn.mos.cms.futurecdn.net/XWDEJ5dUAE2nhK8k3Jk7k7.png"                  },                  {                    "dataCurrency": "USD",                    "dataDiscountedPrice": 299,                    "dataOriginalPrice": 699,                    "dataProduct": "EGOHOME Black Memory Foam Mattress (queen)",                    "dataRetailer": "Amazon",                    "imageURL": "https://cdn.mos.cms.futurecdn.net/hMUemtAejNETLVYxNrktzm.jpg"                  }                ]              }            }          };        }        decodeHTML(html) {          if (!html) return '';          const txt = document.createElement("textarea");          txt.innerHTML = String(html);          return txt.value;        }        extractDealData(item) {          const priceRawStr = String(item.price || item.current_price || '0');          const msrpRawStr = String(item.was_price || item.msrp || item.original_price || '0');          const rawPrice = parseFloat(priceRawStr.replace(/[^\d.]/g, '')) || 0;          const rawMsrp = parseFloat(msrpRawStr.replace(/[^\d.]/g, '')) || 0;          const isCheckPrice = rawPrice === 0 || priceRawStr === '0.00' || priceRawStr === '0';                    let originalImageUrl = item.image || item.image_url || item.product_image || '';          let imageUrl = originalImageUrl;          if ((!imageUrl || isCheckPrice) && item.model_image_url) {             imageUrl = item.model_image_url;             originalImageUrl = imageUrl;          } else if ((!imageUrl || isCheckPrice) && item.model_image) {             imageUrl = item.model_image;             originalImageUrl = imageUrl;          }                    if (imageUrl) {            imageUrl = imageUrl.replace(/-(\d+)-(\d+)(\.[a-z.]+)$/i, '$3');          }                    let fallbackImage = '';          if (originalImageUrl && originalImageUrl !== imageUrl) {             fallbackImage = originalImageUrl;          } else if (item.model_image && item.model_image !== imageUrl) {             fallbackImage = item.model_image;          } else if (item.model_image_url && item.model_image_url !== imageUrl) {             fallbackImage = item.model_image_url;          }                    const rawCurrency = item.currency || item.currency_symbol || '$';                    let savingLabel = item.percentage_saving_label || '';          if (!savingLabel && rawMsrp > rawPrice && rawPrice > 0) {            const pct = Math.round(((rawMsrp - rawPrice) / rawMsrp) * 100);            if (pct > 0) {              savingLabel = `${pct}% OFF`;            }          }                    const isPrime = item.shipping && item.shipping.prime === true;                    let scoreRaw = (item.review_score !== undefined && item.review_score !== null && item.review_score > 0) ? parseFloat(item.review_score) : null;          let starRating = 0;          if (scoreRaw !== null) {            starRating = Math.round((scoreRaw > 10 ? scoreRaw / 20 : scoreRaw / 2) * 2) / 2;          }                    return {            id: item.offer_id || item.link || item.url || item.offer_link || Math.random().toString(),            url: item.link || item.url || item.offer_link || '#',            image: imageUrl,            fallbackImage: fallbackImage,            title: item.name || item.title || item.model_name || item.product_name || 'Unknown Product',            brand: item.brand || '',            productName: item.model_name || item.product_name || item.name || '',            merchant: item.merchant_name || item.merchant || item.retailer || 'Retailer',            price: item.price !== undefined ? String(item.price) : '0.00',            currency: this.decodeHTML(rawCurrency),            msrp: item.was_price || item.msrp || item.original_price || null,            rawPrice: rawPrice,            rawMsrp: rawMsrp,            hasWasPrice: (item.was_price !== undefined && item.was_price !== null),            isCheckPrice: isCheckPrice,            savingLabel: savingLabel,            isPrime: isPrime,            starRating: starRating > 0 ? starRating : null,            modelId: item.model_id || '',            productKey: item.product_key || '',            merchantId: (item.merchant && typeof item.merchant === 'object') ? item.merchant.id || '' : '',            matchId: item.match_id || '',            merchantNetwork: (item.merchant && typeof item.merchant === 'object') ? item.merchant.an || '' : '',            merchantUrl: (item.merchant && typeof item.merchant === 'object') ? item.merchant.url || '' : '',            modelBrand: item.model_brand || item.brand || '',            modelParent: item.model_parent || ''          };        }        sortData() {          const sortVal = this.sortSelect ? this.sortSelect.value : (this.getViewMode() === 'savings_squad' ? 'date_desc' : 'discount_desc');          if (sortVal === 'price_asc') {            this.deals.sort((a, b) => a.rawPrice - b.rawPrice);          } else if (sortVal === 'price_desc') {            this.deals.sort((a, b) => b.rawPrice - a.rawPrice);          } else if (sortVal === 'discount_desc') {            this.deals.sort((a, b) => {              const aDiscount = a.rawMsrp > a.rawPrice ? (a.rawMsrp - a.rawPrice) : 0;              const bDiscount = b.rawMsrp > b.rawPrice ? (b.rawMsrp - b.rawPrice) : 0;              return bDiscount - aDiscount;            });          } else if (sortVal === 'date_desc') {             this.deals.sort((a, b) => {                let dateA = 0;                let dateB = 0;                if (a && a.modifiedDate) {                   const valA = Array.isArray(a.modifiedDate) ? a.modifiedDate[0] : a.modifiedDate;                   dateA = new Date(valA).getTime();                   if (isNaN(dateA)) dateA = 0;                }                if (b && b.modifiedDate) {                   const valB = Array.isArray(b.modifiedDate) ? b.modifiedDate[0] : b.modifiedDate;                   dateB = new Date(valB).getTime();                   if (isNaN(dateB)) dateB = 0;                }                return dateB - dateA;             });          }        }        getFilteredDeals() {          let filteredDeals = [...this.deals];                    if (this.dealModeToggle && this.dealModeToggle.checked) {            filteredDeals = filteredDeals.filter(d => d.hasWasPrice || (d.msrp && d.rawMsrp > d.rawPrice));          }                    return filteredDeals;        }        showLoading() {          const _div = '<' + '/div>';          const skeletonCardHtml = `            \x3Cdiv class="tg-df-card">              \x3Cdiv class="tg-df-card-image-box">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-img">${_div}              ${_div}              \x3Cdiv class="tg-df-card-body">                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text title">${_div}                \x3Cdiv class="tg-df-card-footer mt-auto">                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text short" style="height:24px;">${_div}                  \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text" style="height:44px; margin-top:8px;">${_div}                ${_div}              ${_div}            ${_div}`;          this.grid.innerHTML = Array(4).fill(skeletonCardHtml).join('');        }        showError() {          const _div = '<' + '/div>';          this.grid.innerHTML = `\x3Cdiv class="tg-df-message">            An error occurred while finding deals. Please check your connection and try again.          ${_div}`;        }        escapeHTML(str) {          if (!str) return '';          return String(str).replace(/[&<>'"]/g, tag => ({              '&': '&', '<': '<', '>': '>', "'": ''', '"': '"'          }[tag] || tag));        }                bindCouponButtons() {          const btns = this.root.querySelectorAll('.tg-df-tag-coupons');          btns.forEach(btn => {            btn.addEventListener('click', (e) => {              e.preventDefault();              e.stopPropagation();              const merchant = btn.getAttribute('data-merchant');              this.openVouchersModal(merchant);            });          });                    const closeBtn = this.root.querySelector('#tg-df-vouchers-close');          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (closeBtn) {            closeBtn.onclick = () => this.closeVouchersModal();          }          if (backdrop) {            backdrop.onclick = (e) => {              if (e.target === backdrop) this.closeVouchersModal();            };          }        }                closeVouchersModal() {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          if (backdrop) backdrop.classList.remove('active');        }                async checkMerchantsCouponsBulk(merchants) {          if (!merchants || merchants.length === 0) return {};          const controller = new AbortController();          const timeoutId = setTimeout(() => controller.abort(), 4000);          try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchants.join(','));            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '120');            url.searchParams.append('origin', 'widgets-clientside');                        let res; try { res = await fetch(url.toString(), { signal: controller.signal }); } catch (e) { return {}; }            clearTimeout(timeoutId);            if (!res.ok) return {};            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        const foundMerchants = new Set();            offers.forEach(o => {              let mName = o.merchant_name || o.merchant || o.retailer;              if (mName && typeof mName === 'object') mName = mName.name;              if (mName) foundMerchants.add(String(mName).toLowerCase());            });            const resultMap = {};            merchants.forEach(m => {              if (m) resultMap[m] = foundMerchants.has(String(m).toLowerCase());            });            return resultMap;          } catch (e) {            return {};          }        }                async openVouchersModal(merchantName) {          const backdrop = this.root.querySelector('#tg-df-vouchers-modal');          const title = this.root.querySelector('#tg-df-vouchers-title');          const content = this.root.querySelector('#tg-df-vouchers-content');                    if (!backdrop || !content) return;                    // HACK: Hide closing tags          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h4 = '<' + '/h4>';          const _svg = '<' + '/svg>';          const _circle = '<' + '/circle>';          const _polyline = '<' + '/polyline>';          const _rect = '<' + '/rect>';          const _path = '<' + '/path>';                    title.innerText = `${merchantName} Coupons & Deals`;          content.innerHTML = `\x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}                               \x3Cdiv class="tg-df-skeleton tg-df-skeleton-text">${_div}`;          backdrop.classList.add('active');                    try {            const area = this.getAreaCode();            const url = new URL('https://search-api.fie.future.net.uk/widget.php');            url.searchParams.append('model_name', 'Everything');            url.searchParams.append('language', 'en-GB');            if (area) url.searchParams.append('area', area);            url.searchParams.append('combine_product_types', '1');            url.searchParams.append('filter_merchant_name', merchantName);            url.searchParams.append('all_filters', 'false');            url.searchParams.append('exclude_unlabelled', 'false');            url.searchParams.append('include_specs', 'false');            url.searchParams.append('sort', 'voucher');            url.searchParams.append('distinct_merchants', 'natural');            url.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');            url.searchParams.append('rows', '50');            url.searchParams.append('origin', 'widgets-clientside');                        const res = await fetch(url.toString());            if (!res.ok) throw new Error('API Error');            const data = await res.json();                        let offers = [];            if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {              offers = data.widget.data.offers;            } else if (data && data.data && Array.isArray(data.data.offers)) {              offers = data.data.offers;            } else if (Array.isArray(data)) {              offers = data;            } else if (data && Array.isArray(data.offers)) {              offers = data.offers;            } else if (data && data.offers && Array.isArray(data.offers.offer)) {              offers = data.offers.offer;            } else if (data && Array.isArray(data.data)) {              offers = data.data;            }                        if (offers.length === 0) {              content.innerHTML = `\x3Cdiv class="tg-df-message">No vouchers currently available for ${this.escapeHTML(merchantName)}.${_div}`;              return;            }                        content.innerHTML = offers.map((v, idx) => {              let offerObj = v;              if (v.offers && v.offers.offer) {                offerObj = Array.isArray(v.offers.offer) ? v.offers.offer[0] : v.offers.offer;              } else if (v.offer) {                offerObj = Array.isArray(v.offer) ? v.offer[0] : v.offer;              }              let logoUrl = v.logo_url || offerObj.logo_url || '';              if (!logoUrl && v.merchant) {                if (Array.isArray(v.merchant) && v.merchant.length > 0) logoUrl = v.merchant[0].logo_url || '';                else logoUrl = v.merchant.logo_url || '';              }                            const offerName = offerObj.name || offerObj.title || v.name || v.title || 'Special Offer';              const endTime = offerObj.end_time || v.end_time || '';              const linkUrl = offerObj.link || offerObj.url || v.link || v.url || '#';                            let foundVoucherCode = '';              const findVoucherCode = (obj) => {                if (!obj || typeof obj !== 'object') return;                if (obj.type === 'voucher_code' && obj.display_value) {                  foundVoucherCode = obj.display_value;                  return;                }                if (Array.isArray(obj)) {                  for (const item of obj) {                    findVoucherCode(item);                    if (foundVoucherCode) return;                  }                } else {                  for (const k in obj) {                    if (Object.prototype.hasOwnProperty.call(obj, k)) {                      findVoucherCode(obj[k]);                      if (foundVoucherCode) return;                    }                  }                }              };              findVoucherCode(offerObj);              if (!foundVoucherCode) findVoucherCode(v);                            const voucherCode = foundVoucherCode || offerObj.voucher_code || v.voucher_code || '';              const codeHtml = voucherCode ? `\x3Cspan class="tg-df-voucher-code" data-action="copy-code" data-code="${this.escapeHTML(voucherCode)}" title="Copy to clipboard">                \x3Cspan class="tg-df-voucher-code-text">${this.escapeHTML(voucherCode)}${_span}                \x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px;flex-shrink:0;" class="tg-df-voucher-copy-icon">                  \x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2">${_rect}                  \x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">${_path}                ${_svg}              ${_span}` : '';                            const logoHtml = logoUrl                 ? `\x3Cimg src="${this.escapeHTML(logoUrl)}" alt="${this.escapeHTML(offerName)}" class="tg-df-voucher-logo" />`                 : `\x3Cdiv class="tg-df-voucher-logo" style="background:#e2e8f0;">${_div}`;                            let expiryHtml = '';              if (endTime) {                let dStr = endTime;                if (!isNaN(dStr) && String(dStr).length === 10) dStr = Number(dStr) * 1000;                const d = new Date(dStr);                if (!isNaN(d.getTime())) {                  const options = { year: 'numeric', month: 'short', day: 'numeric' };                  expiryHtml = `                    \x3Cdiv class="tg-df-voucher-expiry">                      \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                        \x3Ccircle cx="12" cy="12" r="10">${_circle}                        \x3Cpolyline points="12 6 12 12 16 14">${_polyline}                      ${_svg}                      Expires ${d.toLocaleDateString(undefined, options)}                    ${_div}`;                }              }              const revenueIdVal = generateRevenueId(linkUrl, offerName, merchantName, null);              const rewrittenLinkUrl = rewriteAffiliateLink(linkUrl, area, revenueIdVal);              return `                \x3Ca href="${this.escapeHTML(rewrittenLinkUrl)}" target="_blank" rel="noopener nofollow" class="tg-df-voucher-item"                  data-action="voucher-click"                  data-product-name="${this.escapeHTML(offerName)}"                  data-merchant-name="${this.escapeHTML(merchantName)}"                  data-analytics-id="${this.escapeHTML(offerObj.offer_id || offerObj.id || v.id || '')}"                  data-price=""                  data-previous-price=""                  data-original-link="${this.escapeHTML(linkUrl)}"                  data-revenue-id="${revenueIdVal}"                  data-index="${idx}"                  data-total="${offers.length}"                  data-in-stock="true"                  data-currency="USD"                  data-model-id="${this.escapeHTML(offerObj.model_id || v.model_id || offerObj.id || v.id || '')}"                  data-merchant-id="${this.escapeHTML(offerObj.merchant_id || offerObj.merchant?.id || '')}"                >                  ${logoHtml}                  \x3Cdiv class="tg-df-voucher-content">                    \x3Ch4 class="tg-df-voucher-title">${this.escapeHTML(offerName)}${_h4}                    ${codeHtml}                    ${expiryHtml}                  ${_div}                ${_a}              `;            }).join('');                        // Attach copy functionality            const copyBtns = content.querySelectorAll('[data-action="copy-code"]');            copyBtns.forEach(btn => {              btn.addEventListener('click', async (e) => {                e.preventDefault();                e.stopPropagation();                                const code = btn.getAttribute('data-code');                if (!code) return;                                try {                  const copyToClipboard = async (text) => {                     if (window.navigator.clipboard && window.isSecureContext) {                        try { await window.navigator.clipboard.writeText(text); return; } catch (e) {}                     }                     const textArea = document.createElement("textarea");                     textArea.value = text;                     textArea.style.position = "fixed";                     document.body.appendChild(textArea);                     textArea.focus();                     textArea.select();                     document.execCommand('copy');                     textArea.remove();                  };                  await copyToClipboard(code);                                    // Visual feedback                  btn.classList.add('copied');                  const textSpan = btn.querySelector('.tg-df-voucher-code-text');                  const iconSvg = btn.querySelector('.tg-df-voucher-copy-icon');                                    const origText = textSpan.innerText;                  const origIcon = iconSvg.innerHTML;                                    textSpan.innerText = 'Copied!';                  iconSvg.innerHTML = `\x3Cpolyline points="20 6 9 17 4 12">${_polyline}`;                                    setTimeout(() => {                    if (btn) {                      btn.classList.remove('copied');                      if (textSpan) textSpan.innerText = origText;                      if (iconSvg) iconSvg.innerHTML = origIcon;                    }                  }, 2000);                                    trackElementInteraction({                    id: 'voucher-code-copy',                    name: 'Copy Voucher Code',                    label: `Copied ${code} for ${merchantName}`                  });                } catch (err) {                  console.warn('Failed to copy text: ', err);                }              });            });            // Attach voucher click tracking            const voucherBtns = content.querySelectorAll('[data-action="voucher-click"]');            voucherBtns.forEach(btn => {              btn.addEventListener('click', (e) => {                if (e.target.closest('[data-action="copy-code"]')) return;                                const productName = btn.getAttribute('data-product-name');                const merchantNameAttr = btn.getAttribute('data-merchant-name');                const productId = btn.getAttribute('data-analytics-id');                const price = parseFloat(btn.getAttribute('data-price')) || null;                const prevPriceStr = btn.getAttribute('data-previous-price');                const previousPrice = prevPriceStr ? parseFloat(prevPriceStr) : null;                const originalLink = btn.getAttribute('data-original-link');                const rewrittenLink = btn.getAttribute('href');                const revenueId = btn.getAttribute('data-revenue-id');                const index = parseInt(btn.getAttribute('data-index'), 10) || 0;                const inStock = btn.getAttribute('data-in-stock') === 'true';                const totalText = btn.getAttribute('data-total');                const totalDeals = parseInt(totalText, 10) || 0;                const productCategoryName = 'deals';                const trackingParams = {                  widgetId: this.widgetId,                  productCategoryName: productCategoryName,                  product: {                    modelId: btn.getAttribute('data-model-id') || null,                    matchId: btn.getAttribute('data-match-id') || null,                    brand: btn.getAttribute('data-model-brand') || null,                    parent: btn.getAttribute('data-model-parent') || null,                    name: productName,                    price: price,                    previousPrice: previousPrice,                    link: rewrittenLink,                    originalLink: originalLink,                    inStock: inStock                  },                  zeroBasedProductIndexOrNull: index,                  totalDealsOrProducts: totalDeals,                   merchant: {                    id: btn.getAttribute('data-merchant-id') || null,                    network: btn.getAttribute('data-merchant-network') || null,                    url: btn.getAttribute('data-merchant-url') || null,                    name: merchantNameAttr                  },                  revenueId: revenueId,                  widgetTypeName: this.widgetTypeName,                  isoCurrencyCode: btn.getAttribute('data-currency') || 'USD'                };                if (typeof trackDealClick === 'function') {                  trackDealClick(trackingParams);                }              });            });                                  } catch (e) {            console.warn(e);            content.innerHTML = `\x3Cdiv class="tg-df-message">Failed to load vouchers.${_div}`;          }        }        render() {          try {            if (this.getViewMode() === 'savings_squad' && this.airedaleTags.length > 0) {              if (this.categoryFilterWrapper) {                 this.categoryFilterWrapper.style.display = 'flex';              }              if (this.categoryFilter) {                 const _option = '<' + '/option>';                 let optionsHtml = `\x3Coption value="all">All Categories${_option}`;                 this.airedaleTags.forEach(tag => {                    const isSelected = this.activeDealTag === tag ? 'selected' : '';                    optionsHtml += `\x3Coption value="${this.escapeHTML(tag)}" ${isSelected}>${this.escapeHTML(tag)} (${this.airedaleTagCounts[tag] || 0})${_option}`;                 });                 this.categoryFilter.innerHTML = optionsHtml;                 this.categoryFilter.value = this.activeDealTag || 'all';              }            } else {               if (this.categoryFilterWrapper) {                  this.categoryFilterWrapper.style.display = 'none';               }            }            const displayDeals = this.getFilteredDeals();          // HACK: Hide closing tags from the CMS HTML sanitizer so it doesn't strip them during in-page injection          const _div = '<' + '/div>';          const _span = '<' + '/span>';          const _a = '<' + '/a>';          const _h3 = '<' + '/h3>';          const _p = '<' + '/p>';          const _strong = '<' + '/strong>';          const _sup = '<' + '/sup>';          const _button = '<' + '/button>';          if (displayDeals.length === 0) {            if (this.currentQuery.length > 2 || (this.getViewMode() === 'savings_squad')) {              if (this.deals.length > 0) {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No deals match your selected filters.                ${_div}`;              } else if (this.getViewMode() === 'savings_squad' && this.currentQuery.length <= 2) {                 // Do not show "no exact matches" if query is empty for savings_squad                 this.grid.innerHTML = '';              } else {                 this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                  No exact matches found for "\x3Cstrong>${this.escapeHTML(this.currentQuery)}${_strong}". Try adjusting your search term.                ${_div}`;              }            } else {              this.grid.innerHTML = `\x3Cdiv class="tg-df-message">                Search product or category names to discover the best deals from across the web.              ${_div}`;            }            return;          }          let dealsHtml = displayDeals.slice(0, this.displayLimit).map((deal, index) => {            try {               const currencySym = this.escapeHTML(deal.currency);               const isoCurrencyCode = normalizeCurrency(currencySym);               const escapedPrice = this.escapeHTML(deal.price);               const escapedMsrp = this.escapeHTML(deal.msrp);               const areaCode = this.getAreaCode();                              const revenueId = generateRevenueId(deal.url, deal.title, deal.merchant, null);               const originalLink = deal.url;               const rewrittenLink = rewriteAffiliateLink(deal.url, areaCode, revenueId);                        const productCategoryName = 'deals';            const dataAttr = `              data-action="${deal.isCheckPrice ? 'view-similar-click' : 'deal-click'}"              data-analytics-id="${this.escapeHTML(deal.externalProductId || deal.id || '')}"              data-product-name="${this.escapeHTML(deal.title)}"              data-merchant-name="${this.escapeHTML(deal.merchant)}"              data-price="${deal.rawPrice || ''}"              data-previous-price="${deal.rawMsrp || ''}"              data-original-link="${this.escapeHTML(originalLink)}"              data-revenue-id="${revenueId}"              data-index="${index}"              data-total="${displayDeals.length}"              data-in-stock="${deal.inStock !== false}"              data-currency="${this.escapeHTML(isoCurrencyCode)}"              data-model-id="${this.escapeHTML(deal.modelId || '')}"              data-product-key="${this.escapeHTML(deal.productKey || '')}"              data-merchant-id="${this.escapeHTML(deal.merchantId || '')}"            `;                        let priceGroupHtml = '';            let isSavingsSquadMode = this.getViewMode() === 'savings_squad';            let ctaText = 'View Deal';            let formattedPrice = '';            let msrpHtml = '';                        if (deal.isCheckPrice) {              ctaText = isSavingsSquadMode ? 'View Deal' : 'Check Price';              if (isSavingsSquadMode) {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                  ${_div}                `;              } else {                priceGroupHtml = `                  \x3Cdiv class="tg-df-card-merchant-wrapper">                    \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                  ${_div}                  \x3Cdiv class="tg-df-card-price-group">                    \x3Cspan class="tg-df-card-price" style="font-size: 15px; font-weight: 500; font-style: italic;">See price at retailer${_span}                  ${_div}                `;              }            } else {              // Format Price              formattedPrice = escapedPrice.includes(currencySym)                 ? escapedPrice                 : `${currencySym}${escapedPrice}`;                              // Format MSRP              msrpHtml = deal.msrp && deal.rawMsrp > deal.rawPrice                ? `\x3Cspan class="tg-df-card-msrp">${escapedMsrp.includes(currencySym) ? escapedMsrp : currencySym + escapedMsrp}${_span}`                : '';                              priceGroupHtml = `                \x3Cdiv class="tg-df-card-merchant-wrapper">                  \x3Cspan class="tg-df-card-merchant-pill" title="${this.escapeHTML(deal.merchant)}">${this.escapeHTML(deal.merchant)}${_span}                ${_div}                \x3Cdiv class="tg-df-card-price-group">                  ${isSavingsSquadMode ? '' : `                  \x3Cspan class="tg-df-card-price">${formattedPrice}${_span}                  ${msrpHtml}                  `}                ${_div}              `;            }                        const discountBadgeHtml = deal.savingLabel && !deal.isCheckPrice              ? `\x3Cspan class="tg-df-card-discount-badge">${this.escapeHTML(deal.savingLabel)}${_span}`              : '';                          // HACK for CMS            const _button = '<' + '/button>';            const _svg = '<' + '/svg>';            const _path = '<' + '/path>';            const _rect = '<' + '/rect>';            const _circle = '<' + '/circle>';            const _polyline = '<' + '/polyline>';            const _line = '<' + '/line>';                        let badgesHtml = '';            const primeBadge = deal.isPrime ? `              \x3Cspan class="tg-df-tag tg-df-tag-prime">                \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">                  \x3Cpath d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">${_path}                ${_svg} Prime              ${_span}            ` : '';                        const couponsBadge = deal.merchant && deal.merchant.toLowerCase().includes('amazon') ? '' : `              \x3Cdiv class="tg-df-coupon-wrapper" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:inline-flex; align-items:center;">                \x3Cdiv class="tg-df-coupon-spinner">${_div}                \x3Cbutton type="button" class="tg-df-tag tg-df-tag-coupons" data-action="coupons-click" data-merchant="${this.escapeHTML(deal.merchant)}" style="display:none;">                  \x3Csvg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">                    \x3Cpath d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z">${_path}                    \x3Cline x1="7" y1="7" x2="7.01" y2="7">${_line}                  ${_svg} Coupons                ${_button}              ${_div}            `;                        // Note: We always add coupons badge if there's a chance, but to allow 3-line titles we check wrapper display state            badgesHtml = `              \x3Cdiv class="tg-df-card-badges">                ${primeBadge}                ${couponsBadge}              ${_div}            `;            const _linearGradient = '<' + '/linearGradient>';            const _polygon = '<' + '/polygon>';            const _stop = '<' + '/stop>';            const _defs = '<' + '/defs>';                        let starHtml = '';            if (deal.starRating) {              let rating = deal.starRating;                            if (rating > 0) {                const fullStars = Math.floor(rating);                const halfStar = (rating - fullStars) >= 0.5 ? 1 : 0;                const emptyStars = Math.max(0, 5 - fullStars - halfStar);                const blue = '#1f69ff'; // Tom's guide brand color from VIEW DEAL button                const gray = '#cbd5e1';                                const starSvgFull = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="${blue}" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                const gradId = 'half_grad_' + Math.floor(Math.random()*1000000);                const starSvgHalf = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" stroke="${blue}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cdefs>\x3ClinearGradient id="${gradId}" x1="0" x2="1" y1="0" y2="0">\x3Cstop offset="50%" stop-color="${blue}">${_stop}\x3Cstop offset="50%" stop-color="transparent">${_stop}${_linearGradient}${_defs}                  \x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26" fill="url(#${gradId})">${_polygon}${_svg}`;                                  const starSvgEmpty = `\x3Csvg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="${gray}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">\x3Cpolygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26">${_polygon}${_svg}`;                                let stars = [];                for (let i=0; i<fullStars; i++) stars.push(starSvgFull);                if (halfStar) stars.push(starSvgHalf);                for (let i=0; i<emptyStars; i++) stars.push(starSvgEmpty);                                starHtml = `\x3Cdiv class="tg-df-card-stars" style="display:flex;align-items:center;margin-bottom:8px;font-size:13px;font-weight:600;color:var(--tg-df-text-muted);">                  \x3Cspan style="margin-right:6px;">Tom's Guide:${_span}                  \x3Cdiv style="display:flex;gap:2px;">                    ${stars.join('')}                  ${_div}                ${_div}`;              }            }            let htmlOutput = '';            if (isSavingsSquadMode) {              htmlOutput += `              \x3Cdiv class="hawk-deal-widget-container tg-df-mobile-only" data-collapsible="true">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''} style="margin-bottom: 10px;">` : ''}                \x3Cdiv class="hawk-deal-widget-wrap">                  \x3Cdiv class="hawk-deal-widget-image-container">                    \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" rel="sponsored noopener" target="_blank" class="hawk-affiliate-link-deal-widget" ${dataAttr}>                      \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="hawk-lazy-image-deal-widget" loading="lazy" width="140" height="160" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                    ${_a}                  ${_div}                  \x3Cdiv class="hawk-deal-widget-text-cta-container">                    \x3Cdiv class="hawk-deal-widget-text-body-container">                      \x3Cdiv class="hawk-deal-widget-text-body-main">                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          ${deal.isCheckPrice ? `                            \x3Cspan class="hawk-deal-widget-title-product-title">${this.escapeHTML(deal.title)}${_span}                          ` : `                            \x3Cspan class="hawk-deal-widget-title-product-title">${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_span}                          `}                        ${_a}                        ${!deal.isCheckPrice && deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan class="hawk-deal-widget-title-was-price">was ${currencySym}${escapedMsrp}${_span}                          ${_a}                        ` : ''}                        \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-container" rel="sponsored noopener" target="_blank" ${dataAttr}>                          \x3Cspan class="hawk-deal-widget-title-retailer-price">                            ${!deal.isCheckPrice ? `                              \x3Cspan class="hawk-deal-widget-title-price">now ${formattedPrice}${_span}                              \x3Cspan class="hawk-deal-widget-title-retailer"> at ${this.escapeHTML(deal.merchant)}${_span}                            ` : `                              \x3Cspan class="hawk-deal-widget-title-price">See price at ${this.escapeHTML(deal.merchant)}${_span}                            `}                          ${_span}                        ${_a}                        ${deal.description ? `\x3Cdiv class="hawk-deal-widget-text-body-description">\x3Cp>${this.escapeHTML(deal.description)}${_p}${_div}` : ''}                      ${_div}                    ${_div}                    \x3Cdiv class="hawk-deal-widget-footer">                      \x3Cdiv class="hawk-deal-widget-button-wrapper">                        \x3Cdiv class="hawk-deal-widget-preferred-partner-wrapper">                          \x3Ca data-google-interstitial="false" aria-label="View ${this.escapeHTML(deal.title)} on ${this.escapeHTML(deal.merchant)}" href="${this.escapeHTML(rewrittenLink)}" class="hawk-affiliate-link-deal-button" rel="sponsored noopener" target="_blank" ${dataAttr}>                            \x3Cspan>${deal.isCheckPrice ? 'Check Price' : 'View Deal'}${_span}                          ${_a}                        ${_div}                      ${_div}                    ${_div}                  ${_div}                ${_div}              ${_div}              `;            }            htmlOutput += `              \x3Cdiv class="tg-df-card ${isSavingsSquadMode ? 'tg-df-desktop-only' : ''}">                ${this.editorMode ? `\x3Cinput type="checkbox" class="tg-df-deal-checkbox" data-id="${this.escapeHTML(deal.id)}" ${this.selectedDeals.has(deal.id) ? 'checked' : ''}>` : ''}                \x3Cdiv class="tg-df-card-image-box">                  ${discountBadgeHtml}                  \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;">                    \x3Cimg ${deal.image ? `src="${this.escapeHTML(deal.image)}"` : ''} alt="${this.escapeHTML(deal.title)}" class="tg-df-card-image" loading="lazy" onerror="${deal.fallbackImage ? `if(!this.dataset.fb) { this.dataset.fb='1'; this.src='${this.escapeHTML(deal.fallbackImage)}'; } else { this.style.opacity='0'; }` : `this.style.opacity='0';`}">                  ${_a}                ${_div}                \x3Cdiv class="tg-df-card-body">                  ${starHtml}                  ${badgesHtml}                  \x3Ch3 class="tg-df-card-title tg-df-custom-savings-squad-title" title="${this.escapeHTML(deal.title)}">                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" disable-tracking="true" target="_blank" rel="noopener nofollow" style="text-decoration: none; color: inherit;">                      ${isSavingsSquadMode                         ? (deal.isCheckPrice                             ? (deal.title && deal.title.includes(':')                                 ? `\x3Cstrong>${this.escapeHTML(deal.title.substring(0, deal.title.indexOf(':') + 1))}${_strong}\x3Cspan style="color: #1f69ff; font-weight: normal;">${this.escapeHTML(deal.title.substring(deal.title.indexOf(':') + 1))}${_span}`                                : this.escapeHTML(deal.title)                              )                             : `\x3Cstrong>${deal.brand ? this.escapeHTML(deal.brand) + ' ' : ''}${this.escapeHTML(deal.productName || deal.title || '')}:${_strong} ${deal.rawMsrp && deal.rawMsrp > deal.rawPrice ? `\x3Cspan style="color: #d0021b; text-decoration: line-through; font-weight: normal; margin-right: 4px;">was ${currencySym}${escapedMsrp}${_span} ` : ''}\x3Cspan style="color: #1f69ff; font-weight: normal;">now ${formattedPrice} at ${this.escapeHTML(deal.merchant)}${_span}`                          )                        : this.escapeHTML(deal.title)                      }                    ${_a}                  ${_h3}                  ${deal.description ? `\x3Cp style="font-size: 13px; color: var(--tg-df-text-muted); margin-bottom: 12px; line-height: 1.4;">${this.escapeHTML(deal.description)}${_p}` : ''}                  \x3Cdiv class="tg-df-card-footer">                    ${priceGroupHtml}                    \x3Ca href="${this.escapeHTML(rewrittenLink)}" ${dataAttr} target="_blank" rel="noopener nofollow" class="tg-df-card-cta ${isSavingsSquadMode ? 'tg-df-cta-savings-squad' : ''}" style="text-decoration: none;">${ctaText}${_a}                  ${_div}                ${_div}              ${_div}            `;                        return htmlOutput;            } catch (e) {               console.log("Error rendering deal in map for index", index, typeof deal === 'object' ? JSON.stringify(deal) : deal, "MSG:", e.message);               return '';            }          }).join('');                    if (displayDeals.length > this.displayLimit || ((this.getViewMode() === 'carousel' || this.getViewMode() === 'auto') && displayDeals.length > 0 && displayDeals.length % ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12) === 0)) {            if (this.getViewMode() === 'carousel') {               dealsHtml += `                 \x3Cbutton type="button" class="tg-df-load-more-card tg-df-load-more">                   \x3Csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom: 8px;">\x3Cpath d="M5 12h14">\x3C/path>\x3Cpath d="m12 5 7 7-7 7">\x3C/path>\x3C/svg>                   Load More                 ${_button}               `;            } else {               dealsHtml += `                 \x3Cdiv style="width: 100%; display: flex; justify-content: center; margin-top: 16px; grid-column: 1 / -1;">                   \x3Cbutton type="button" class="tg-df-tag-outline tg-df-load-more" style="padding: 8px 24px; border-radius: 100px; font-weight: 600; font-size: 14px; cursor: pointer; display: flex; align-items: center;">Load More${_button}                 ${_div}               `;            }          }                    this.grid.innerHTML = dealsHtml;          // Inject JSON-LD          try {            let targetNode = this.hostContainer || document.head;            let jsonLdScript = targetNode.querySelector('#tg-df-json-ld-' + this.widgetId);            if (!jsonLdScript) {                jsonLdScript = document.createElement('script');                jsonLdScript.type = 'application/ld+json';                jsonLdScript.id = 'tg-df-json-ld-' + this.widgetId;                targetNode.appendChild(jsonLdScript);            }            const jsonLdData = {              "@context": "https://schema.org",              "@type": "ItemList",              "itemListElement": displayDeals.slice(0, this.displayLimit).map((deal, index) => {                 let isoCurrency = "USD";                 if (deal.currency === '£') isoCurrency = "GBP";                 else if (deal.currency === '€') isoCurrency = "EUR";                 else if (deal.currency === 'A$') isoCurrency = "AUD";                 else if (deal.currency === 'CA$') isoCurrency = "CAD";                 const areaCode = typeof this.getAreaCode === 'function' ? this.getAreaCode() : 'US';                 const revenueId = typeof generateRevenueId === 'function' ? generateRevenueId(deal.url, deal.title, deal.merchant, null) : '';                 const rewrittenLink = typeof rewriteAffiliateLink === 'function' ? rewriteAffiliateLink(deal.url, areaCode, revenueId) : deal.url;                 return {                   "@type": "ListItem",                   "position": index + 1,                   "item": {                     "@type": "Product",                     "name": deal.title,                     "image": deal.image || "",                     "description": deal.description || "",                     "brand": {                       "@type": "Brand",                       "name": deal.brand || ""                     },                     "offers": {                       "@type": "Offer",                       "priceCurrency": isoCurrency,                       "price": deal.rawPrice || 0,                       "url": rewrittenLink,                       "seller": {                         "@type": "Organization",                         "name": deal.merchant || ""                       }                     }                   }                 };              }).filter(item => item.item.name)            };            jsonLdScript.textContent = JSON.stringify(jsonLdData);          } catch(e) { console.warn("JSON-LD generation failed", e); }                    let gridWrapper = this.grid.parentElement;          if (gridWrapper && gridWrapper.classList.contains('tg-df-grid-wrapper')) {             let rightChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-right');             let leftChevron = gridWrapper.querySelector('.tg-df-carousel-scroll-left');             if (this.getViewMode() === 'carousel') {                 // The observer set up in setupScrollListeners handles visibility.                 if (rightChevron) rightChevron.style.display = 'flex';                 if (leftChevron) leftChevron.style.display = 'none'; // reset correctly             } else {                 if (rightChevron) rightChevron.style.display = 'none';                 if (leftChevron) leftChevron.style.display = 'none';             }          }                    const loadMoreBtn = this.grid.querySelector('.tg-df-load-more');          if (loadMoreBtn) {            loadMoreBtn.addEventListener('click', async () => {              if (typeof trackElementInteraction === 'function') {                trackElementInteraction({ id: 'load-more', name: 'Load more', label: 'Load More Results' });              }              if (displayDeals.length <= this.displayLimit) {                 loadMoreBtn.innerHTML = `                  <svg class="tg-df-spinner" style="width: 16px; height: 16px; display: inline-block; vertical-align: middle; margin-right: 8px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83"/></svg>                  Loading...                 `;                 loadMoreBtn.disabled = true;                 await this.fetchDeals(this.currentQuery, true);              } else {                 this.displayLimit += ((this.rowsSelect && this.rowsSelect.value) ? parseInt(this.rowsSelect.value, 10) : 12);                 this.render();              }            });          }                      this.bindCouponButtons();            this.checkAndUpdateCoupons();                        // Allow hawklinks.js to discover and rewrite our widget links             // by appending the .article-body class and manually triggering processArticle.            let container = this.root.classList.contains('tg-df-container') ? this.root : this.root.querySelector('.tg-df-container');            if (container && !container.classList.contains('article-body')) {               container.classList.add('article-body');            }            setTimeout(() => {               if (this.grid && !this.grid.classList.contains('article-body')) this.grid.classList.add('article-body');            if (!this.processArticleFired) {                  this.processArticleFired = true;                  document.dispatchEvent(new CustomEvent('processArticle', { detail: { element: this.root } }));               }            }, 50);          } catch(e) {            console.warn("Widget render error", e);          }        }                async checkAndUpdateCoupons() {          const wrappers = Array.from(this.root.querySelectorAll('.tg-df-coupon-wrapper'));          if (wrappers.length === 0) return;                    const merchants = [...new Set(wrappers.map(w => w.getAttribute('data-merchant')).filter(Boolean))];          if (merchants.length === 0) return;          const couponResultsMap = await this.checkMerchantsCouponsBulk(merchants);                    for (const merchant of merchants) {            const hasCoupons = !!couponResultsMap[merchant];            const merchantWrappers = wrappers.filter(w => w.getAttribute('data-merchant') === merchant);            merchantWrappers.forEach(wrapper => {              const spinner = wrapper.querySelector('.tg-df-coupon-spinner');              const btn = wrapper.querySelector('.tg-df-tag-coupons');                            if (spinner) spinner.style.display = 'none';                            if (hasCoupons && btn) {                btn.style.display = 'inline-flex';              } else if (!hasCoupons) {                wrapper.style.display = 'none';              }            });          }        }        updateFloatingCopyBar() {          if (!this.editorBar || !this.editorSelectedCount) return;          if (this.editorMode && this.selectedDeals.size > 0) {            this.editorBar.style.display = 'flex';            this.editorSelectedCount.innerText = this.selectedDeals.size;          } else {            this.editorBar.style.display = 'none';          }        }        async copySelectedDealsToCMS() {           function htmlToSlate(htmlString) {              if (!htmlString) return [{ type: 'paragraph', children: [{ text: '' }] }];              let doc;              if (typeof window !== 'undefined' && window.DOMParser) {                 doc = new DOMParser().parseFromString(htmlString, 'text/html');              } else {                 doc = document.implementation.createHTMLDocument('');                 doc.body.innerHTML = htmlString;              }                            function parseNode(node, marks = {}) {                  if (node.nodeType === 3) {                      const text = node.textContent;                      if (!text) return null;                      return { text: text, ...marks };                  }                  if (node.nodeType === 1) {                      const tagName = node.tagName.toLowerCase();                      if (tagName === 'br') {                          return { type: 'line-break', children: [{ text: '' }] };                      }                      if (tagName === 'p') {                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return { type: 'paragraph', children };                      }                      if (tagName === 'strong' || tagName === 'b') {                          const newMarks = { ...marks, bold: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'em' || tagName === 'i') {                          const newMarks = { ...marks, italic: true };                          return Array.from(node.childNodes).map(child => parseNode(child, newMarks)).flat().filter(Boolean);                      }                      if (tagName === 'a') {                          const href = node.getAttribute('href') || '';                          let children = Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                          if (children.length === 0) children.push({ text: "" });                          return {                              type: 'link',                              url: href,                              isNoFollow: (node.getAttribute('rel') || '').includes('nofollow'),                              isSponsored: (node.getAttribute('rel') || '').includes('sponsored'),                              isOpenNewTab: node.getAttribute('target') === '_blank',                              isPreventDataRewrite: false,                              children: children                          };                      }                      return Array.from(node.childNodes).map(child => parseNode(child, marks)).flat().filter(Boolean);                  }                  return null;              }                            let blocksArray = [];              let currentParagraphChildren = [];              function flushParagraph() {                  if (currentParagraphChildren.length > 0) {                      blocksArray.push({ type: 'paragraph', children: currentParagraphChildren });                      currentParagraphChildren = [];                  }              }              Array.from(doc.body.childNodes).forEach(node => {                  const parsed = parseNode(node, {});                  const parsedItems = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : []);                  parsedItems.forEach(item => {                      if (item.type === 'paragraph') {                          flushParagraph();                          blocksArray.push(item);                      } else {                          currentParagraphChildren.push(item);                      }                  });              });              flushParagraph();              if (blocksArray.length === 0) {                  blocksArray = [{ type: 'paragraph', children: [{ text: '' }] }];              }              return blocksArray;           }           const blocks = [];                      this.editorCopyBtn.innerHTML = '\x3Cspan class="tg-df-coupon-spinner" style="display:inline-block; margin-right:8px; border-top-color:#fff;">' + '<' + '/span> Copying...';           for (const deal of Array.from(this.selectedDeals.values())) {              const url = deal.url;              const merchant = deal.merchant;              const title = deal.title;              const image = deal.image;              const currentPrice = deal.currency + deal.rawPrice;              const wasPrice = deal.hasWasPrice && deal.rawMsrp > deal.rawPrice ? deal.currency + deal.rawMsrp : '';                            let couponsChildren = [];              try {                  const area = this.getAreaCode();                  const apiUrl = new URL('https://search-api.fie.future.net.uk/widget.php');                  apiUrl.searchParams.append('model_name', 'Everything');                  apiUrl.searchParams.append('language', 'en-GB');                  apiUrl.searchParams.append('area', area);                  apiUrl.searchParams.append('combine_product_types', '1');                  apiUrl.searchParams.append('filter_merchant_name', merchant);                  apiUrl.searchParams.append('all_filters', 'false');                  apiUrl.searchParams.append('exclude_unlabelled', 'false');                  apiUrl.searchParams.append('include_specs', 'false');                  apiUrl.searchParams.append('sort', 'voucher');                  apiUrl.searchParams.append('distinct_merchants', 'natural');                  apiUrl.searchParams.append('filter_product_types', 'vouchers,offer_deals,newsletter');                  apiUrl.searchParams.append('rows', '3');                  apiUrl.searchParams.append('origin', 'widgets-clientside');                                    let res; try { res = await fetch(apiUrl.toString()); } catch (e) { return; }                  if (res.ok) {                      const data = await res.json();                      let offers = [];                      if (data && data.widget && data.widget.data && Array.isArray(data.widget.data.offers)) {                        offers = data.widget.data.offers;                      } else if (data && data.data && Array.isArray(data.data.offers)) {                        offers = data.data.offers;                      }                                            if (offers.length > 0) {                          couponsChildren.push({ text: "Also check out these coupons: ", bold: true });                          offers.slice(0, 3).forEach((offer, idx) => {                              const actualOffer = offer.offer || offer;                              const offerName = actualOffer.name || actualOffer.title || offer.model_name || offer.title || offer.name || 'Coupon';                              const linkUrl = actualOffer.link || actualOffer.url || actualOffer.offer_link || '#';                              couponsChildren.push({ type: "line-break", children: [{ text: "" }] });                              couponsChildren.push({ text: "🎟️ " });                              couponsChildren.push({                                  type: "link",                                  url: linkUrl,                                  isNoFollow: true,                                  isSponsored: false,                                  isOpenNewTab: true,                                  isPreventDataRewrite: false,                                  children: [{ text: offerName, bold: true }]                              });                          });                      }                  }              } catch (err) {                  console.warn('Failed to fetch coupons for', merchant, err);              }              let descriptionValue = [];              if (deal.text) {                 descriptionValue = htmlToSlate(deal.text);              } else {                 const dealDescriptions = [                   `Don't miss out on this fantastic deal for the ${title}. It is currently available at ${merchant} for a highly competitive price.`,                   `We've spotted an excellent price drop on the ${title}. Grab it now at ${merchant} before it's gone.`,                   `The ${title} is currently seeing a generous discount over at ${merchant}. This is a perfect time to buy if you've been holding out.`,                   `If you're in the market for the ${title}, ${merchant} has just the deal for you.`,                   `Score the ${title} for less at ${merchant} right now. This is a rare chance to save big.`,                   `Upgrade your setup with the ${title}, now available at a stellar price via ${merchant}.`                 ];                 const randomDescription = dealDescriptions[Math.floor(Math.random() * dealDescriptions.length)];                 descriptionValue = [                    { type: "paragraph", children: [{ text: randomDescription }] }                 ];              }                            if (couponsChildren.length > 0) {                 let lastBlock = descriptionValue[descriptionValue.length - 1];                 if (lastBlock && lastBlock.type === 'paragraph') {                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children.push({ text: "Also check out these coupons: ", bold: true });                     lastBlock.children.push({ type: "line-break", children: [{ text: "" }] });                     lastBlock.children = lastBlock.children.concat(couponsChildren);                 } else {                     descriptionValue.push({                         type: "paragraph",                         children: [                             { type: "line-break", children: [{ text: "" }] },                             { type: "line-break", children: [{ text: "" }] },                             { text: "Also check out these coupons: ", bold: true },                             { type: "line-break", children: [{ text: "" }] },                             ...couponsChildren                         ]                     });                 }              }              function normalizeCurrencyToISO(symbol) {                const map = { '£': 'GBP', '$': 'USD', 'A$': 'AUD', 'CA$': 'CAD', '€': 'EUR' };                return map[symbol] || symbol;              }              const isoCurrency = normalizeCurrencyToISO(deal.currency);              blocks.push({                 id: (window.crypto && window.crypto.randomUUID) ? window.crypto.randomUUID() : 'cms-' + Date.now() + Math.random(),                 blockTypeName: "deal",                 excludeFrom: [],                 collapsible: false,                 props: {                    description: {                       value: descriptionValue,                       touched: false,                       validationMessage: ""                    },                    image: {                       value: {                          credit: [{ type: "paragraph", children: [{ text: merchant }] }],                          dateCreated: Date.now(),                          dateModified: Date.now(),                          distribution: [],                          fileSize: 0,                          height: 1000,                          id: deal.id,                          imageRights: "",                          src: image,                          name: title + ".jpg",                          tags: [],                          width: 1000                       },                       touched: false,                       validationMessage: ""                    },                    showDealButton: { value: true, touched: false, validationMessage: "" },                    isPreferredPartner: { value: false, touched: false, validationMessage: "" },                    linkHref: { value: url, touched: false, validationMessage: "" },                    linkLabel: { value: "", touched: false, validationMessage: "" },                    linkIsNoFollow: { value: true, touched: false, validationMessage: "" },                    linkIsSponsored: { value: false, touched: false, validationMessage: "" },                    linkIsOpenNewWindow: { value: true, touched: false, validationMessage: "" },                    customPromoFlags: { value: [], touched: false, validationMessage: "" },                    showStarDeal: { value: false, touched: false, validationMessage: "" },                    savingType: { value: "none", touched: false, validationMessage: "" },                    starDealPromoFlag: { value: "", touched: false, validationMessage: "" },                    showEditorsChoice: { value: false, touched: false, validationMessage: "" },                    editorsChoiceTitle: { value: "", touched: false, validationMessage: "" },                    hawkPriceCurrency: { value: { value: isoCurrency, label: isoCurrency }, touched: false, validationMessage: "" },                    hawkPrice: { value: deal.hasWasPrice ? String(deal.rawMsrp) : String(deal.rawPrice), touched: false, validationMessage: "" },                    hawkSalePrice: { value: String(deal.rawPrice), touched: false, validationMessage: "" },                    lastCheckedPriceDate: { value: "", touched: false, validationMessage: "" },                    hawkModel: { touched: false, validationMessage: "" },                    productId: { value: "", touched: false, validationMessage: "" },                    voucherId: { value: "", touched: false, validationMessage: "" },                    brand: { value: deal.brand || merchant, touched: false, validationMessage: "" },                    productName: { value: title, touched: false, validationMessage: "" },                    label: { value: "", touched: false, validationMessage: "" },                    retailer: { value: merchant, touched: false, validationMessage: "" },                    priceCheckError: false                 },                 failedFetchError: ""              });           }           const payload = {              type: "articleBuilderPages",              data: blocks           };           const jsonStr = JSON.stringify(payload);                      if (navigator.clipboard && navigator.clipboard.writeText) {              navigator.clipboard.writeText(jsonStr).then(() => {                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              }).catch(err => {                 console.warn('Failed to copy text: ', err);                 alert('Failed to copy deals to clipboard. See console.');              });           } else {              // Fallback              const textArea = document.createElement("textarea");              textArea.value = jsonStr;              document.body.appendChild(textArea);              textArea.focus();              textArea.select();              try {                 document.execCommand('copy');                 this.editorCopyBtn.innerHTML = 'Copied!';                 setTimeout(() => {                    this.editorCopyBtn.innerHTML = '\x3Csvg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">\x3Crect x="9" y="9" width="13" height="13" rx="2" ry="2"><' + '/rect>\x3Cpath d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"><' + '/path><' + '/svg> Copy to CMS';                 }, 2000);              } catch (err) {                 console.warn('Fallback: Oops, unable to copy', err);                 alert('Fallback: Failed to copy deals to clipboard.');              }              document.body.removeChild(textArea);           }        }      }      // Initialize the Widget      if (document.readyState === 'loading') {        document.addEventListener('DOMContentLoaded', () => new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer }));      } else {        new DealsFinderWidget({ rootId: 'signal-deals-finder-root', rootNode: shadowRoot, hostContainer: hostContainer });      }    })();  </script></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I thought I could be the life of the party with the Soundboks Mix — but its shortcomings make me want to buy another party speaker instead ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-thought-i-could-be-the-life-of-the-party-with-the-soundboks-mix-but-its-shortcomings-make-me-want-to-buy-another-party-speaker-instead</link>
                                                                            <description>
                            <![CDATA[ I've spent the last week testing the Soundboks Mix and while this party speaker is good, its closest competition blows it out of the water. Here's why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">mkHvJHQGw27aP7ygozrSRj</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/JszLChisaE6N7vn4QJyMMD-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 20 Jun 2026 05:15:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/JszLChisaE6N7vn4QJyMMD-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A black Soundboks Mix party speaker]]></media:description>                                                            <media:text><![CDATA[A black Soundboks Mix party speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A black Soundboks Mix party speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/JszLChisaE6N7vn4QJyMMD-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Small, portable Bluetooth speakers can sound really good, but let's be honest: if you're soundtracking a large gathering or party, a small one isn't going to cut it. You need a proper party speaker for that, one that gets incredibly loud and makes your guests feel like they're at a concert. How about one that hits a staggering 121dB, then?</p><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/soundboks-mix-review">Soundboks Mix</a> is perhaps the loudest speaker I've tested yet. It's loud, but even at the highest volume, music doesn't sound too distorted, and the treble and mids remain surprisingly clear. Bass is nothing short of Earth-shaking, and the room-filling sound leaves you drooling. But...</p><div class="product"><a data-dimension112="dc054b3e-61a7-4a29-b6c3-43def3c6fc70" data-action="Deal Block" data-label="The Soundboks Mix is the brand’s portable party speaker, and it packs impressive audio capabilities. Ground-shaking bass, crisp treble, and refined mids make listening to music and soundtracking a party a treat. It’s IP65-rated so it’s protected against the elements, and it comes with a user-friendly companion app for customizing the equalizer. However, there aren’t as many connection ports on it as its closest rival, and it uses Bluetooth 4.2." data-dimension48="The Soundboks Mix is the brand’s portable party speaker, and it packs impressive audio capabilities. Ground-shaking bass, crisp treble, and refined mids make listening to music and soundtracking a party a treat. It’s IP65-rated so it’s protected against the elements, and it comes with a user-friendly companion app for customizing the equalizer. However, there aren’t as many connection ports on it as its closest rival, and it uses Bluetooth 4.2." data-dimension25="$799" href="https://www.amazon.com/Soundboks-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:661px;"><p class="vanilla-image-block" style="padding-top:141.45%;"><img id="sypUHzwyPGjW57FYtGkA6k" name="Soundboks-Mix-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/sypUHzwyPGjW57FYtGkA6k.jpg" mos="" align="middle" fullscreen="" width="661" height="935" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Soundboks Mix is the brand’s portable party speaker, and it packs impressive audio capabilities. Ground-shaking bass, crisp treble, and refined mids make listening to music and soundtracking a party a treat. It’s IP65-rated so it’s protected against the elements, and it comes with a user-friendly companion app for customizing the equalizer. However, there aren’t as many connection ports on it as its closest rival, and it uses Bluetooth 4.2.<a class="view-deal button" href="https://www.amazon.com/Soundboks-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow" data-dimension112="dc054b3e-61a7-4a29-b6c3-43def3c6fc70" data-action="Deal Block" data-label="The Soundboks Mix is the brand’s portable party speaker, and it packs impressive audio capabilities. Ground-shaking bass, crisp treble, and refined mids make listening to music and soundtracking a party a treat. It’s IP65-rated so it’s protected against the elements, and it comes with a user-friendly companion app for customizing the equalizer. However, there aren’t as many connection ports on it as its closest rival, and it uses Bluetooth 4.2." data-dimension48="The Soundboks Mix is the brand’s portable party speaker, and it packs impressive audio capabilities. Ground-shaking bass, crisp treble, and refined mids make listening to music and soundtracking a party a treat. It’s IP65-rated so it’s protected against the elements, and it comes with a user-friendly companion app for customizing the equalizer. However, there aren’t as many connection ports on it as its closest rival, and it uses Bluetooth 4.2." data-dimension25="$799">View Deal</a></p></div><p>Yeah, there's always a "but." It's part and parcel of testing and reviewing products, because few (if any) are perfect. The Mix is no different. Even though I love its sound profile, its drawbacks have left me feeling shortchanged — and when $799 is on the line, you want bang for your buck. There is <em>one </em>speaker out there that's great value for money, and sadly, it ain't the Mix.</p><h2 id="shake-the-ground">Shake the ground</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Syt6GuUeRig4JF24bZU8cG" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/Syt6GuUeRig4JF24bZU8cG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>One of the Soundboks Mix's biggest selling points is that it's get ridiculously loud. At a whopping 121dB, the Mix sounds loud enough to vibrate a glass off a desk if you're indoors, or shake the ground when you're outdoors. Metaphorically speaking, of course — I didn't <em>actually </em>manage to drop a glass off a countertop.</p><p>All that's to say is that you can certainly be the life of the party with the Mix. Whether you're head-banging to bass-heavy rock or dancing to electronic dance music, the Mix has you covered. Two 72W Class D amplifiers powered by a  10-inch woofer and a 1.2-inch dome tweeter cover a frequency response range of 40Hz to 20KHz — typical for a speaker of its demeanour.</p><p>Regardless of the tune I listened to, I was impressed. Lana Del Rey's vocals in ‘<a href="https://open.qobuz.com/album/gcsfc9y5o0or4" target="_blank" rel="nofollow">First Light</a>’ sat front and centre and sounded remarkably clear. The warmth, texture and emotional nuance were reproduced accurately, while subtle details in her delivery found themselves in the spotlight without sounding too clinical. The treble in rock tunes, like ‘<a href="https://open.qobuz.com/track/361933224" target="_blank" rel="nofollow">Elma</a>’ by Yin Yin and ‘<a href="https://open.qobuz.com/track/47683549" target="_blank" rel="nofollow">Echoes</a>’ by Pink Floyd, shone and sounded vibrant without cutting through the rest of the soundstage.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3FmGWRVvPfwtvKddRTvSWD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/3FmGWRVvPfwtvKddRTvSWD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><div  class="fancy-box"><div class="fancy_box-title">Hear me out...</div><div class="fancy_box_body"><p class="fancy-box__body-text">Naturally, I have a lot more to say about the sound quality, which is why my in-depth review is there! Check out my <a data-analytics-id="inline-link" href="https://www.tomsguide.com/audio/bluetooth-speakers/soundboks-mix-review">Soundboks Mix review</a> for all the details.</p></div></div><p>None of that would matter, however, if the Mix didn't do what a party speaker is designed to do: make you dance to electronic tracks, and it manages to do so. The bass in ‘<a href="https://open.qobuz.com/track/400341345" target="_blank" rel="nofollow">Lights Burn Dimmer</a>’ by Fred Again and Jaime T sounded controlled and tight with the EQ set to Indoor. It didn't overpower the rest of the soundstage. Switching the EQ preset to Bass+ made me feel the song in my bones. It was loud and made the ground beneath me shake. I could feel my teeth chattering.</p><p>Turning the volume all the way up to 10 (as you might do if you're hosting a party outdoors) revealed a weakness, though. The bass was still room-filling, but it sounded wobbly and uncontrolled, like the Mix was struggling to keep up with it, or was feeling overwhelmed by it. Truth be told, that's not great news for a party speaker — especially for one that costs just under $800... which, very nicely, brings me to my next point.</p><h2 id="nowhere-to-hide-when-the-competition-is-so-good">Nowhere to hide when the competition is so good</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="WnGYtHHq6oV5ywBFiAwDSh" name="Marshall_Bromley_450_edit" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/WnGYtHHq6oV5ywBFiAwDSh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>When I was testing the Soundboks Mix, I couldn't help but think to myself, "This speaker could be <em>the </em>best party speaker around... if it wasn't competing with the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Marshall Bromley 450</a>." The Bromley 450, Marshall's second-ever party speaker, is a top-notch product that doesn't skimp on features on sound quality. I've thoroughly tested that speaker too, and knowing what it offers for the same money has further highlighted the Mix's flaws to me.</p><div class="product"><a data-dimension112="7fe5201f-9c84-4929-82a7-8197fa2b803b" data-action="Deal Block" data-label="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm to hook up multiple speakers across rooms. Oh, and the reactive LED lighting helps with immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension48="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm to hook up multiple speakers across rooms. Oh, and the reactive LED lighting helps with immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension25="$799" href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1453px;"><p class="vanilla-image-block" style="padding-top:103.23%;"><img id="HjgJt6n3dM7M8i2cDEqMue" name="Marshall Bromley 450" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/HjgJt6n3dM7M8i2cDEqMue.png" mos="" align="middle" fullscreen="" width="1453" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm to hook up multiple speakers across rooms. Oh, and the reactive LED lighting helps with immersion. 40-hour battery life and IP55 waterproofing make it a winner.<a class="view-deal button" href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow" data-dimension112="7fe5201f-9c84-4929-82a7-8197fa2b803b" data-action="Deal Block" data-label="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm to hook up multiple speakers across rooms. Oh, and the reactive LED lighting helps with immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension48="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm to hook up multiple speakers across rooms. Oh, and the reactive LED lighting helps with immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension25="$799">View Deal</a></p></div><p>One of the first things I noticed about the Mix was its lack of ports. All you get is a USB-C port for charging and a 3.5mm jack for wired playback. The Bromley 450 goes above and beyond here, with two XLR/6.35mm combo ports for microphones and acoustic/electric guitars, and RCA ports for keyboards and turntables. It essentially doubles (or triples) as an amplifier and a karaoke machine.</p><p>You've then got the Mix using an old version of Bluetooth: 4.2. That's not <em>bad, </em>per se, but it isn't good either for a speaker that came out in March 2026. Bluetooth 4.2 is an old version at this point. That means shorter range and no way to stream LE or hi-res audio, so you're stuck with the basic SBC codec.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="XwbtGmTpNXUqgU9BykKqpg" name="Marshall_Bromley_450_edit-19" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/XwbtGmTpNXUqgU9BykKqpg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Bromley 450 has yet another ace up its sleeve: 360° True Stereophonic surround sound, which means that regardless of where you're standing in a room, you'll hear the same exceptional sound. This makes listening to your favorite tunes more immersive, something the Mix can't achieve.</p><p>Combine all of this with the wobbly bass and you've got yourself a clear winner. The Mix costs <a href="https://www.amazon.com/Soundboks-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.amazon.co.uk/SOUNDBOKS-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">£599</a>, and the Bromley 450 retails for <a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.argos.co.uk/product/8397942" target="_blank" rel="nofollow">£549</a>, and for the same price, you get versatile connectivity options, better Bluetooth and LE audio, 360° sound, and even integrated stage lights that react to the music.</p><p>I know which speaker I'd personally buy. What do you think? Let me know in the comments below!</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XbQVgO"></div>                            </div>                            <script src="https://kwizly.com/embed/XbQVgO.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/soundboks-mix-review">I just tested Soundboks’ portable party speaker — and it’s so close to be being great</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">I just tested the ‘best party speaker of 2026’ — here's why you should buy the Marshall Bromley 450</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/forget-the-bose-s1-pro-the-brand-new-marshall-bromley-450-just-redefined-party-speakers">Forget Bose — there's no better party speaker on the planet than the brand-new Marshall Bromley 450</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested Soundboks’ portable party speaker — and it’s so close to be being great ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/soundboks-mix-review</link>
                                                                            <description>
                            <![CDATA[ The Soundboks Mix is a powerful and incredibly loud party speaker, which delivers ground-shaking bass and 40 hours of battery life. But it has some flaws. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">vArdHPQmMCrCNNhQyKU75g</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Syt6GuUeRig4JF24bZU8cG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 19 Jun 2026 10:10:42 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/Syt6GuUeRig4JF24bZU8cG-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A black Soundboks Mix party speaker]]></media:description>                                                            <media:text><![CDATA[A black Soundboks Mix party speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A black Soundboks Mix party speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Syt6GuUeRig4JF24bZU8cG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Sometimes, a small speaker isn’t loud enough to soundtrack an evening with friends or a big party. You need a party speaker for that, and the Soundboks Mix is a solid choice. Soundboks’ portable party speaker is built extremely well and is protected against the elements, thanks to its IP65 rating. The sound? Nearly exquisite. The Mix delivers powerful, Earth-shaking bass, vibrant treble, and precise, balanced mids.</p><p>But is it the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> for the money? It costs $799 and features some noteworthy flaws, such as wobbly bass at high volumes, Bluetooth 4.2 only, no 360° sound, and more. If those are compromises you’re willing to make, then the Mix could be perfect for you. Trust me, it sounds really, <em>really </em>good.</p><p>For the complete breakdown, read my full Soundboks Mix review.</p><h2 class="article-body__section" id="section-soundboks-mix-review-specs"><span>Soundboks Mix review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Soundboks-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.amazon.co.uk/SOUNDBOKS-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">£599</a></p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>IP65</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 4.2, 3.5mm wired</p></td></tr><tr><td class="firstcol " ><p><strong>Multi-speaker connectivity</strong></p></td><td  ><p>Yes, up to 5</p></td></tr><tr><td class="firstcol " ><p><strong>Multipoint</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Output power</strong></p></td><td  ><p>2x 72W Class D amplifiers, 1x 10-inch woofer, 1x 1.2-inch dome tweeter</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response</strong></p></td><td  ><p>40Hz-20KHz</p></td></tr><tr><td class="firstcol " ><p><strong>Range</strong></p></td><td  ><p>Not specified</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>40 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>18.9 x 13.4 x 10.6 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>21.38lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-soundboks-mix-review-price-availability"><span>Soundboks Mix review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Syt6GuUeRig4JF24bZU8cG" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/Syt6GuUeRig4JF24bZU8cG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Launched in March 2026, the Soundboks Mix is the <a href="https://www.tomsguide.com/audio/soundboks-4-review">Soundboks 4</a>’s smaller sibling, and it effectively replaces the Soundboks Go as the brand’s most portable party speaker — it’s priced as such too. While the 4 costs $999, the Mix retails for <a href="https://www.amazon.com/Soundboks-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.amazon.co.uk/SOUNDBOKS-Mix-Weatherproof-Rechargeable-Ultra-Loud/dp/B0GLP3S87Y/" target="_blank" rel="nofollow">£599 at Amazon</a>. Given how loud it gets, the Mix is a great party speaker for anyone who doesn’t want to spend nearly a grand on the bigger model.</p><p>The Mix is Soundboks’ answer to the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Marshall Bromley 450</a> ($799) and the JBL PartyBox 520 ($879). It’s got the specs and sound to go toe-to-toe with the Bromley 450, too, but is it worth buying instead of the Marshall? I've reviewed both, so let’s find out.</p><h2 class="article-body__section" id="section-soundboks-mix-review-design"><span>Soundboks Mix review: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="JszLChisaE6N7vn4QJyMMD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/JszLChisaE6N7vn4QJyMMD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Soundboks Mix looks very similar to the Soundboks 4 — similar to how the Marshall Bromley 450 and <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Marshall Bromley 750</a> ($1,299) share design philosophies. You’re getting bang for your buck here as the Mix feels very well-built, featuring an ABS and polycarbonate cabinet, silicone ball corners to protect it from getting damaged, and a detachable steel grill. All in all, it feels sturdy and durable.</p><p>The Mix doesn’t sport any garish LED lighting that makes it look tacky, like on the JBL PartyBox 520 — although I do wish it had some integrated stage lights, like the Bromley 450 does. Branding is fairly minimal too, with the logo sitting in the top left corner. You can buy the speaker in black only, which is no bad thing; the Bromley 450 and PartyBox 520 come in single colors too.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GYJcwZCcUHcGHYGwX8DUDD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/GYJcwZCcUHcGHYGwX8DUDD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As Soundboks’ most compact party speaker, the Mix doesn’t feel too heavy and doesn’t take up much space either. It measures 18.9 x 13.4 x 10.6 inches and weighs 21.38lbs, so it’s about 5lbs lighter than the Bromley 450. To move it around, you can use the built-in carry handle, which is fine, but because there’s only one located in one corner, the Mix feels a little unwieldy to move around. This problem could have been easily solved by installing a suitcase-style handle smack dab in the middle of its side, <em>à la</em> Bromley 450.</p><p>But hey, you can buy a strap to turn the Mix into a backpack… for $59. And it doesn’t come with a charger... which you can also buy separately for $59. The Mix feels to speakers what EA is to gaming: full of microtransactions.</p><h2 id="weatherproofing">Weatherproofing</h2><p>If you want a rugged party speaker that you can use outdoors without worrying too much about it getting rained on, the Mix is a great choice. The speaker is IP65-rated which means it’s fully dust-tight and protected against rain and moisture. That’s slightly better than the Marshall Bromley 450 which is IP55-rated. When I was testing the Mix outdoors, it started drizzling and knowing that the speaker was IP65-rated reassured me.</p><h2 id="controls">Controls</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3FmGWRVvPfwtvKddRTvSWD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/3FmGWRVvPfwtvKddRTvSWD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>There isn’t a lot going on in terms of controls on the Mix. All the physical buttons and volume dial are located on the speaker’s right edge, and these include the volume knob, TeamUp button for wirelessly linking up to five Soundboks speakers together, and the power button for, well, turning the speaker on and off. That’s about it. The buttons give good tactile feedback when pressed, and are fairly straightforward to understand.</p><h2 id="connectivity">Connectivity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SVDVY2PHpuqyycvZDw6YBD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/SVDVY2PHpuqyycvZDw6YBD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Mix utilizes Bluetooth 4.2 to connect wirelessly to your smartphone, laptop or other devices, and it features multipoint connectivity for simultaneously connecting up to two devices. Bluetooth 4.2 is disappointing, though, as it means there’s limited codec support, so you only get the standard SBC codec. No AAC and no LE audio, unfortunately.</p><p>This older version also limits the speaker’s maximum operating range to 40m only. Not great for a party speaker. What if you’re soundtracking a big gathering and you’re far away from the speaker, and the connection drops when you move out of range? That’s one way to kill the mood.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="yMsmMvtNJcyKQykMqrFSnD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/yMsmMvtNJcyKQykMqrFSnD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>In comparison, the Marshall Bromley 450 utilizes the newer Bluetooth 5.3 with support for AAC and LC3, and sports many more connectivity options, such as RCA and two XLR/6.35mm combo jacks for plugging in instruments or microphones. One thing the Mix and Bromley 450 have in common, though, is 3.5mm wired playback. But if you want a versatile party speaker, I’d choose the Bromley 450 any day.</p><p>Like I alluded to earlier, there's a TeamUp button on the Mix for wirelessly connecting up to five Soundboks speakers. There's also a Bond button with arrows, located right under the TeamUp button. When it lights up in green, it means the speaker is connected to another speaker it has been linked to in the past. You can also become the "Host" when other speakers are connected to yours, and control them via the smartphone app (more on that shortly).</p><h2 class="article-body__section" id="section-soundboks-mix-review-sound-quality"><span>Soundboks Mix review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jhMuR9CbKmAXM8EQq9xeXD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/jhMuR9CbKmAXM8EQq9xeXD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>There’s no dearth of tech squeezed into the Soundboks Mix’s portable body. It packs two 72W Class D amplifiers powered by a 10-inch woofer and a 1.2-inch dome tweeter. It can go all the way up to 121dB — a little louder than the Marshall Bromley 450 (100dB). The Mix covers a frequency response range of 40Hz to 20KHz, which is typical for party speakers as it delivers crisp highs and deep bass, perfect for pop, rock, EDM, what-have-you. I listened to my usual mix of testing songs on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, the <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service</a> for hi-res audio.</p><p>To test the Mix’s midrange performance, I listened to ‘<a href="https://open.qobuz.com/album/gcsfc9y5o0or4" target="_blank" rel="nofollow">First Light</a>’ by Lana Del Rey, and I was instantly impressed. Lana’s vocals sat front and centre with remarkable clarity, and the speaker captured and accurately reproduced the warmth, texture and emotional nuance that define the James Bond theme song. Subtle details in her delivery, such as her short, sharp breaths, shone without sounding too clinical or like they were piercing through the soundscape. I also appreciated the Mix preserving the tonal balance even at the highest volume — the track never once sounded distorted, and it still sounded engaging and cinematic.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="EiD67JXUNuFZoSMpLha6mG" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/EiD67JXUNuFZoSMpLha6mG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>There’s nothing the Mix can’t handle, and it manages to deliver vibrant treble without making it sound too overzealous. The psychedelic/electronic guitar notes landed with impressive clarity and shimmered in ‘<a href="https://open.qobuz.com/track/361933224" target="_blank" rel="nofollow">Elma</a>’ by Yin Yin, while the drums’ hi-hats added depth to the track without becoming harsh or fatiguing.</p><p>Similarly, in Pink Floyd’s ‘<a href="https://open.qobuz.com/track/47683549" target="_blank" rel="nofollow">Echoes</a>,’ I thoroughly enjoyed the delicate balance between cymbal work and the ambient or atmospheric sound effects. The Mix added a brilliant airiness to the track, making me feel like I was there with the band as they <a href="https://www.youtube.com/watch?v=JQ2pTamaqQ4" target="_blank" rel="nofollow">recorded the song at Pompeii</a>.</p><p>But this is a party speaker, after all, so I had to test it by listening to an electronic track you can dance to. ‘<a href="https://open.qobuz.com/track/400341345" target="_blank" rel="nofollow">Lights Burn Dimmer</a>’ by Fred Again and Jaime T highlights the Mix’s greatest strength: bass. With the EQ set to Indoor, the bass sounds very controlled and tight, giving the track a great backbone without overpowering the rest of the soundstage. I then tried the Bass+ EQ preset which turns the bass all the way up to 10.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:962px;"><p class="vanilla-image-block" style="padding-top:56.24%;"><img id="Syt6GuUeRig4JF24bZU8cG" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/v2/t:0,l:524,cw:962,ch:541,q:80/Syt6GuUeRig4JF24bZU8cG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>While the song still sounded powerful and the bass was room-filling, I couldn’t help but notice that the bassline sounded wobbly, like it was too much for the Mix to handle. This was indoors so I tried this preset outdoors, and the bass still sounded slightly muddy — an issue I never encountered when testing the Marshall Bromley 450.</p><p>It’s also important to note that the Mix doesn’t feature 360° surround sound, which means that you can only really appreciate music when standing directly in front of the speaker. If you want a more immersive listening experience, and want your party guests to be able to hear your tunes regardless of where they’re standing, I’d recommend the Bromley 450 which features True Stereophonic 360° sound.</p><p><em>Listen along to my review with the Soundboks Mix testing playlist:</em></p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/65793089?zone=GB-en"></iframe><h2 class="article-body__section" id="section-soundboks-mix-review-app"><span>Soundboks Mix review: App</span></h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/ogr744HPDqdbhZrAqcJNzX.jpg" alt="Soundboks mobile app screenshots" /><figcaption><small role="credit">Soundboks / Tom's Guide</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/74Rp82WHWWx762bPoNj7iX.jpg" alt="Soundboks mobile app screenshots" /><figcaption><small role="credit">Soundboks / Tom's Guide</small></figcaption></figure></figure><p>The Soundboks Mix is accompanied by the brand’s app for all its speakers, and it’s available for free on <a href="https://soundboks.co.uk/pages/app" target="_blank" rel="nofollow">iOS and Android</a>. This is one area in which the Mix upstages the Marshall Bromley 450. The Bromley 450’s app is decent but not great, and the Mix offers a lot more in terms of customization.</p><p>Via the user-friendly app, you can make adjustments to the five-band custom equalizer, choose one of three EQ presets, control other Soundboks speakers you’ve paired with the Mix, control the volume, and, of course, update the firmware. I also like that the EQ presets have quirky descriptions. For instance, the Bass+ preset is described as, “More bass, just like you wanted. Yes, you.” I dig it.</p><h2 class="article-body__section" id="section-soundboks-mix-review-battery-life"><span>Soundboks Mix review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Zcz5bn23Qc9mujvj2LWZUD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/Zcz5bn23Qc9mujvj2LWZUD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Soundboks Mix offers superb battery life as it can last up to 40 hours between charges. Battery life will naturally depend on the volume and EQ presets, and happily, the app tells you how long the speaker will last when certain EQ presets are active. If you’re playing at full volume or have the Bass+ preset enabled, the battery life drops to eight hours. You can use any USB-C cable to charge the Mix.</p><p>Both the Marshall Bromley 750 and the Marshall Bromley 450 also pack 40-hour batteries. The Mix upstages the JBL PartyBox 520’s 15-hour and the Sony ULT Tower 9’s 25-hour batteries, too.</p><p>Similar to both the Bromleys, the Mix’s battery pack is removable and it can even be used to charge your smartphone, laptop and other devices. This is a handy feature to have especially if you’re out and about and not near a charging outlet.</p><h2 class="article-body__section" id="section-soundboks-mix-review-verdict"><span>Soundboks Mix review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="i9BiXXNabWbv4Mg8hxpnPD" name="Soundboks_Mix_" alt="A black Soundboks Mix party speaker" src="https://cdn.mos.cms.futurecdn.net/i9BiXXNabWbv4Mg8hxpnPD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Soundboks Mix isn’t without its compromises, but when it comes to sound quality, it still delivers a wonderful listening experience. Party speakers need to put out big sound, and the Mix can get incredibly loud without distortion. Earth-shaking bass is balanced well with detailed treble and mids, and though the bass can get a little wobbly at high volumes, it’s still enjoyable.</p><p>Designed to withstand the elements, the Mix is IP65-rated and is reinforced to stand the test of time. That said, for the same price of $799, the Marshall Bromley 450 offers better value for money. More ports for hooking up instruments, better connectivity thanks to Bluetooth 5.3, and 360° sound.</p><p>If all you want is full-bodied sound, the Mix is a great choice, but the extra versatility of similarly-priced rivals stops it achieving one of our very highest scores.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living and this $50 offering rivals big names like JBL and Bose — here's what I like and don't like about the Tribit StormBox Micro 3 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-this-sub-usd70-offering-from-tribit-rivals-big-names-like-jbl-and-bose-heres-what-i-like-and-dont-like-about-it</link>
                                                                            <description>
                            <![CDATA[ After using the Tribit StormBox Micro 3 for a few weeks, it's become my go-to speaker for indoors and in the backyard. Here's why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">6yifRuMeSEmBMyhPtpkDyD</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/mpYmpr4wAMUdFoxsr362Cg-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 15 Jun 2026 05:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/mpYmpr4wAMUdFoxsr362Cg-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit StormBox Micro 3]]></media:description>                                                            <media:text><![CDATA[Tribit StormBox Micro 3]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit StormBox Micro 3]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/mpYmpr4wAMUdFoxsr362Cg-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As a reviews writer here at Tom's Guide, I get my hands on a lot of the latest tech, including some of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>. And funnily enough, some of my favorites have been some of the cheapest offerings. </p><p>Tribit is a budget audio brand, but its Bluetooth speakers always turn out to be some of my favorites. I recently tested the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review">Tribit StormBox Micro 3,</a> and it totally earns it's 4.5 star rating. </p><p>The speaker is only $64, and can often be found on sale for even less. Like right now, it's down to <a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S">$49 at Amazon U.S</a>.</p><div class="product"><a data-dimension112="f05d8fe3-c877-4865-9d92-522d03a24fab" data-action="Deal Block" data-label="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent." data-dimension48="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent." data-dimension25="$49" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="RS3PDefgkukwjHkV9sCy9M" name="tribit-stormbox-micro-3-portable-bluetoo-9e0eed43-f6d4-445f-be8d-6cac88998b28.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/RS3PDefgkukwjHkV9sCy9M.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow" data-dimension112="f05d8fe3-c877-4865-9d92-522d03a24fab" data-action="Deal Block" data-label="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent." data-dimension48="The Tribit StormBox Micro 3 offers an IP68 rating, a companion app for EQ customization, and simple controls that make the speaker a breeze to use. It has 24 hours of battery life and can even be used as a portable charger. But most importantly, the audio performance really is excellent." data-dimension25="$49">View Deal</a></p></div><h2 id="excellent-audio-performance">Excellent audio performance</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="AdztFXRYm2qRnPoAbredeU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/AdztFXRYm2qRnPoAbredeU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Of course, sound is the most important thing to consider when buying a new Bluetooth speaker, and the Tribit StormBox Micro 3 nails it.  For such a small speaker, it creates a big sound. </p><p>And when the BassX setting is deployed, you have home-filling sound. I love using this feature in the house or just in the backyard while taking care of some chores. You can also switch up the EQ settings in the Tribit companion app, but the BassX button on the speaker makes switching up the sound incredibly easy, and it suits most music genres. </p><h2 id="top-choice-for-durability">Top choice for durability</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="5C4rm2BEgQpXe64xtKfNaU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/5C4rm2BEgQpXe64xtKfNaU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>With a durability rating of IP68, this speaker can take on anything. With this rating, the speaker can actually withstand water submersion and is completely dust-tight. </p><p>You don't need to worry about dropping it, either, as it's been rated to survive falls from as much as four feet. I'm the world's worst butterfinger, so I did end up dropping the speaker a few times, and it was completely fine.  </p><h2 id="all-day-battery">All-day battery</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9JFp65GWDw98dPHu7u9yXU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/9JFp65GWDw98dPHu7u9yXU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The 24-hour battery life is one of the best things about this speaker. It's double the battery life of some competitors, and it doesn't suffer too much at high volumes. </p><p>If using the BassX settings, the battery drains faster, but I was still able to get a good 18 hours, which is very impressive. </p><h2 id="not-exactly-micro">Not exactly "micro"</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dLJQsthExUW6jmoyP5wHVU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/dLJQsthExUW6jmoyP5wHVU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Though the StormBox Micro 3 is small, Tribit actually makes smaller speakers than this. The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a>, for example, is a lot smaller, and I find it far easier to carry around with me. </p><p>It's also surprisingly heavy, but that's down to the speaker being magnetic. This feature is incredibly convenient, and in some ways makes it worth the extra weight. </p><p>To find out more about the Bluetooth speaker and what it can do, you can read my full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review">Tribit StromBox Micro 3 review</a>.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review#section-tribit-stormbox-micro-3-review-sound-quality"><strong>Tribit has done it again — the brand-new StormBox Micro 3 rivals JBL for under $70</strong></a></li><li><a href="https://www.tomsguide.com/audio/you-can-take-a-portable-bluetooth-speaker-with-you-camping-but-heres-why-its-not-the-best-idea-to-use-it-on-your-hike"><strong>You can take a portable Bluetooth speaker with you camping, but here's why it's not the best idea to use it on your hike</strong></a></li><li><a href="https://www.tomsguide.com/ai/ever-wonder-why-chatgpt-is-free-the-answer-is-far-more-calculated-than-you-might-think"><strong>Ever wonder why ChatGPT is free? The answer is far more calculated than you might think</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Tribit has done it again — the brand-new StormBox Micro 3 rivals JBL for under $70 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review</link>
                                                                            <description>
                            <![CDATA[ The Tribit StormBox Micro 3 proves that you don’t need to spend a lot of cash to get a durable speaker with awesome sound. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">GixpRa8FQxJtpdg6BjjXKc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ZdvddFbSvYJEvrGg6Ske2V-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 10 Jun 2026 06:15:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/ZdvddFbSvYJEvrGg6Ske2V-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit StormBox Micro 3 in black photographed in front of a blue background]]></media:description>                                                            <media:text><![CDATA[Tribit StormBox Micro 3 in black photographed in front of a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit StormBox Micro 3 in black photographed in front of a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ZdvddFbSvYJEvrGg6Ske2V-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I’m a big fan of Tribit’s speakers, and the Tribit Strombox Micro 3 has joined the ranks as one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> I’ve tested. It has seriously excellent audio performance for a variety of genres, EQ customization, and simple controls. On top of that, it’s waterproof, dustproof, and dropproof. The 24-hour battery life is the cherry on top, and it can even be used as a portable charger for your phone in a pinch. </p><p>The only downside is that some of the EQ presets, such as ‘Rock’, compress the sound, and you lose the full effect of the wide soundstage. </p><p>Some people may not love the basic appearance, but I don’t mind it as I think it fits in any situation. </p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-specs"><span>Tribit StormBox Micro 3 review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow">$64</a> / <a href="https://www.amazon.co.uk/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow">£62</a></p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>IP68</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 6.0</p></td></tr><tr><td class="firstcol " ><p><strong>Multi-speaker connectivity</strong></p></td><td  ><p>True Wireless Stereo (TWS)</p></td></tr><tr><td class="firstcol " ><p><strong>Range</strong></p></td><td  ><p>147.6 feet</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>24 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>4.4 x 4.3 x 1.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>0.73 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, Blue, Gray White</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-price-availability"><span>Tribit StormBox Micro 3 review: Price & availability</span></h2><p>The Tribit StormBox Micro 3 is available to purchase from Amazon for <a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow">$64</a> / <a href="https://www.amazon.co.uk/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow">£62</a>. It comes in three different colors, including black, blue and grayish white. This is the third iteration of Tribit’s StormBox and is only slightly more expensive than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-2-review">Tribit StormBox Micro 2</a>, which costs $59. </p><p>The StormBox Micro 3 is also more expensive than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a>, which has become my most reliable portable speaker. The PocketGo costs $34 and has huge sound without a huge price tag. </p><p>While the StormBox Micro 2 is a cheap offering in the Bluetooth speaker world, there are even cheaper options: The cheapest Bluetooth speaker I’ve tested is the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tozo-pe1-review#section-tozo-pe1-review-price-availability">Tozo PE1</a>, which costs $29, but it’s worth spending more for the better bass performance offered by the StormBox Micro 3.</p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-design"><span>Tribit StormBox Micro 3 review: Design</span></h2><p>At 4.4 x 4.3 x 1.8 inches and 0.7 pounds, I think the Tribit StormBox Micro 3 is a little big to call itself ‘micro,’ but it’s still small enough to fit nicely into your backpack. It also has a flexible strap on the back so it can be attached to anything with a diameter of under 1.1 inches, such as handlebars on a bike. </p><p>It was a lot heavier than I expected, but because it has a magnet inside, it can be mounted to any magnetic surface, which is probably the best way to carry it around.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="C3Gi3PUm4SKxCjN3sJbNuU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/C3Gi3PUm4SKxCjN3sJbNuU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I tested the black color, which has white buttons and a mesh overlay in front of the speaker. It looks a lot like the previous StormBox Micro speaker, but with more rounded edges, which softens the rugged look. </p><p>The speaker has a durability rating of IP68, meaning it is completely waterproof and dustproof. It’s also been military drop-tested up to a height of four feet. </p><h3 id="controls-2">Controls</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9Hk48wSZACfyKtv8ozhNkU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/9Hk48wSZACfyKtv8ozhNkU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The controls on the Tribit StormBox Micro 3 are very simple, and since I’ve used Tribit speakers in the past, including the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit StormBox Lava</a> ($129) and the Tribit PocketGo, the controls felt very natural to me. </p><p>On the side of the speaker, you'll find a power button, a Bluetooth connection button, a BassX EQ preset button, and a TWS (True Wireless Stereo) button for linking speakers.</p><p>On top, there are larger buttons for volume, play, and pause. I like that these buttons are big and easily accessible, as they're the ones you'll reach for most.</p><h3 id="connectivity-2">Connectivity</h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="QWtdRLRBHi8vkzMgq8CF5V" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/QWtdRLRBHi8vkzMgq8CF5V.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Tribit StormBox Micro 3 uses Bluetooth 6.0. The speaker has a connection range of nearly 150 feet, so I was able to walk away from the speaker all the way into my garden without the connection breaking up. </p><p>The speaker also has TWS (True Wireless Stereo, not to be confused with True Wireless), which means you can connect multiple speakers together at the same time to create a stereo setup. </p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-sound-quality"><span>Tribit StormBox Micro 3 review: Sound quality</span></h2><p>For such a small speaker, the Tribit StormBox Micro 3 creates a big sound.  I think the speaker’s signature sound with the BassX setting already sounds great, but I got the best sound when using a custom EQ setting. </p><p>To test bass performance, I listened to <em>Tonight (I Wish I Was Your Boy)</em> by The 1975 using the BassX EQ. The punchy bass drives this song, and the speaker did a good job of keeping it controlled. It sounded clean while not overpowering the other components of the song, which still sounded sharp and balanced. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9WyziVp5FTGpjSMkxAbUvU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/9WyziVp5FTGpjSMkxAbUvU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I then turned to the mid-performance of the speaker by listening to <em>Ok Love You Bye</em> by Olivia Dean. This track has a lot of layers that played perfectly with Tribit's signature EQ. The woodwind and brass instruments were very prominent throughout, and the vocals remained strong. I could hear how broad the soundstage is when listening to this song, and I was impressed by the performance. </p><p>Finally, I tested out the treble by listening to <em>In Bloom</em> by Neck Deep. This track is very bright with a complex percussion rhythm from the drums. For this track, I made a U-shaped  Custom EQ.  There were no issues with muddy sounds, and although there’s a lot going on, the instrument separation was excellent.</p><p>Overall, I was impressed with the way it played my favorite songs, but I wouldn’t recommend using the EQ presets, as some caused a lot of compression.</p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-app"><span>Tribit StormBox Micro 3 review: App</span></h2><p>The StormBox Micro 3 can be used with the Tribit app, which is available to download for free. </p><p>In the app, you’ll find six EQ presets you can choose from, or you can make your own custom EQ settings. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="HqSYnpzhSxC7pM3iP6eKtX" name="Tribit StormBox Micro 3 app" alt="Screenshots from the Tribit app showing the EQ controls of the Tribit StormBox Micro 3" src="https://cdn.mos.cms.futurecdn.net/HqSYnpzhSxC7pM3iP6eKtX.jpg" mos="" align="middle" fullscreen="" width="1510" height="850" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tribit)</span></figcaption></figure><p>The EQ uses nine bands, so there’s a lot of scope to make changes to the sound to fit your personal preference. </p><p>You can also set a sleep timer for automatic shut-off of the speaker, which is pretty useful, as well as see the remaining battery on the speaker. </p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-battery-life"><span>Tribit StormBox Micro 3 review: Battery life</span></h2><p>Speaking of battery life, the Tribit StormBox Micro 3 has a rated battery life of 24 hours when used at half volume. This is plenty loud enough for casual listening, but if you’re using the speaker outdoors and need to listen a little louder, the battery will then drain faster. </p><p>Still, 24 hours is plenty of battery, and four more hours than you get with the Tribit PocketGo. This battery life is far superior to the JBL Go 5, which only has 10 hours. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9JFp65GWDw98dPHu7u9yXU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/9JFp65GWDw98dPHu7u9yXU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Should you find yourself out of juice and in need of a quick boost, just 15 minutes of charging time with the included USB-C cable provides three hours of playback while a full charge takes around two hours. </p><p>Just like the Tribit StormBox Lava, the Micro 3 has reverse charging, which means you can use it as a portable charger in a pinch if you need to charge your phone.</p><h2 class="article-body__section" id="section-tribit-stormbox-micro-3-review-verdict"><span>Tribit StormBox Micro 3 review: Verdict</span></h2><p>Tribit has managed to make me love a budget speaker yet again. It's waterproof, dustproof, and drop-proof, making it an ideal option for anyone who wants to use the speaker outdoors. </p><p>Its companion app can be used for EQ customization, and the simple controls make it a breeze to use even without your phone nearby. The 24 hours of battery life mean you can listen all day, and the speaker can even be used as a portable charger in a pinch. But most importantly, the audio performance really is <em>excellent</em>.</p><p>For something slightly lighter, you could consider the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-clip-5-review">JBL Clip 5</a> for $79. This speaker also has a more sturdy clip at the top, rather than a flexible strap. The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5</a> also gives beautiful sound for $54. The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-miniroll-review-tiny-but-mighty#section-ue-miniroll-review">UltimateEars Miniroll</a> costs $79 and also has a strap attachment at the back. This speaker is even lighter but is around the same size as the StormBox Micro 3. </p><p>For its price, however, the StormBox Micro 3 is tough to beat.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ You can take a portable Bluetooth speaker with you camping, but here's why it's not the best idea to use it on your hike ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/you-can-take-a-portable-bluetooth-speaker-with-you-camping-but-heres-why-its-not-the-best-idea-to-use-it-on-your-hike</link>
                                                                            <description>
                            <![CDATA[ Many people love listening to music while on walks, but headphones are the best listening option so you don't disturb the wildlife. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">mbzDA9fGDG5Af56fMQAtKJ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/4Yq4rr3TLdoAT6dLRWsmJZ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 08 Jun 2026 10:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/4Yq4rr3TLdoAT6dLRWsmJZ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide / Ashley Thieme]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit StormBox Micro 3 Bluetooth Speaker and woman hiking on a trail]]></media:description>                                                            <media:text><![CDATA[Tribit StormBox Micro 3 Bluetooth Speaker and woman hiking on a trail]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit StormBox Micro 3 Bluetooth Speaker and woman hiking on a trail]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/4Yq4rr3TLdoAT6dLRWsmJZ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>For me, hiking is a form of escapism. Getting out into nature is one of the easiest ways to switch off from the stressors of day-to-day life and reflect on what's happening, or block it out altogether. </p><p>But another way I like to unwind is by listening to music. It seems only natural to want to combine the two pastimes.</p><p>When I head to a campsite for the weekend, I usually like to bring one of the best Bluetooth speakers with me, like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a> or the <a href="https://tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-3-review">Tribit StormBox Micro 3</a>. And while it can be tempting to take the speaker into the woods to soundtrack a hike, that's probably not the best idea. Here's why. </p><h2 id="sound-travels-farther-than-you-think">Sound travels farther than you think</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ZdvddFbSvYJEvrGg6Ske2V" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/ZdvddFbSvYJEvrGg6Ske2V.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Even though it's just you and your speaker walking the trail, the sound it's making travels a lot farther than you'd think. In an open area, there's not much around to stop the sound from traveling, and not to mention the echo that can be caused by the shape of the landscape. </p><p>Many people, including myself, like to sit and listen to the sounds of their surroundings when on their walk. When the sound carries, it can disturb other people on their trail appreciating these sounds — or, worse, disturb the sleeping habits of nocturnal animals. </p><p>To combat this, it's best to use some of the <a href="https://www.tomsguide.com/best-picks/best-over-ear-headphones">best over-ear headphones</a> to keep the listening party private. </p><div class="product"><a data-dimension112="5b44dc22-2c41-4032-97df-df45fe93a3f3" data-action="Deal Block" data-label="best headphones" data-dimension48="best headphones" data-dimension25="$248" href="https://www.amazon.com/Marshall-Canceling-Over-Ear-Bluetooth-Headphones/dp/B0DFDT1TWC" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="xmTbqHyw3cvfuFwFbQYqQk" name="Marshall Monitor III prod image" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/xmTbqHyw3cvfuFwFbQYqQk.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Marshall Monitor III made our list of the <a href="https://www.tomsguide.com/us/best-headphones,review-1988.html" data-dimension112="5b44dc22-2c41-4032-97df-df45fe93a3f3" data-action="Deal Block" data-label="best headphones" data-dimension48="best headphones" data-dimension25="$248">best headphones</a> because of their incredible battery life. These retro-looking headphones deliver up to 100 hours of battery life are great for listening on the go. They're also extremely comfy, and we really appreciate their intuitive physical controls. <a class="view-deal button" href="https://www.amazon.com/Marshall-Canceling-Over-Ear-Bluetooth-Headphones/dp/B0DFDT1TWC" target="_blank" rel="nofollow" data-dimension112="5b44dc22-2c41-4032-97df-df45fe93a3f3" data-action="Deal Block" data-label="best headphones" data-dimension48="best headphones" data-dimension25="$248">View Deal</a></p></div><h2 id="better-safe-than-sorry">Better safe than sorry</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="xvDCHhtwLtKyDJzMMtqPwZ" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/xvDCHhtwLtKyDJzMMtqPwZ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This probably goes without saying, but when you're out walking, hiking, or running, you need to stay aware of your surroundings. Depending on the difficulty of the trail, it's important to stay aware of all of the sounds around you. </p><p>When you block out environmental sounds, you can miss out on important safety cues like wild animals, falling rocks, or even someone nearby who needs help. Even when listening at lower volumes, it can block out these ambient sounds. </p><p>I always think it's best to take in the sounds of nature too. As I mentioned, it helps me clear my mind and can be very good for lowering stress hormones. </p><p>A nice compromise here are open earbuds like the <a href="https://www.tomsguide.com/audio/earbuds/sony-linkbuds-clip-review">Sony LinkBuds Clip</a>, <a href="https://www.tomsguide.com/audio/earbuds/soundcore-aeroclip-review">Soundcore AeroClip</a> or <a href="https://www.tomsguide.com/audio/earbuds/bose-ultra-open-earbuds">Bose Ultra Open</a>. These earbuds let you listen to your music without disturbing nearby wildlife as well as let you keep an ear out for potential danger.</p><div class="product"><a data-dimension112="74f6b89c-edb7-487e-a7e1-8b503104177b" data-action="Deal Block" data-label="4 stars in our review" data-dimension48="4 stars in our review" data-dimension25="$229" href="https://www.amazon.com/dp/B0FDKR4RVP/?" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:62.59%;"><img id="wjSgGFFpyDJzdztK3MZ64S" name="Bose ultra open" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wjSgGFFpyDJzdztK3MZ64S.jpg" mos="" align="middle" fullscreen="" width="679" height="425" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Bose Ultra Open perfected the open earbud formula. They have a comfortable, non-invasive fit, solid battery life, and they sound better than you might expect from open buds. They got <a href="https://www.tomsguide.com/audio/earbuds/bose-ultra-open-earbuds" data-dimension112="74f6b89c-edb7-487e-a7e1-8b503104177b" data-action="Deal Block" data-label="4 stars in our review" data-dimension48="4 stars in our review" data-dimension25="$229">4 stars in our review</a>, where we loved their simple controls and surprising lack of sound leakage. <a class="view-deal button" href="https://www.amazon.com/dp/B0FDKR4RVP/?" target="_blank" rel="nofollow" data-dimension112="74f6b89c-edb7-487e-a7e1-8b503104177b" data-action="Deal Block" data-label="4 stars in our review" data-dimension48="4 stars in our review" data-dimension25="$229">View Deal</a></p></div><h2 id="impact-on-wildlife">Impact on wildlife</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dLJQsthExUW6jmoyP5wHVU" name="Tribit StormBox Micro 3" alt="Tribit StormBox Micro 3 in black photographed in front of a blue background" src="https://cdn.mos.cms.futurecdn.net/dLJQsthExUW6jmoyP5wHVU.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Most importantly, if you care about wild animals' wellbeing, playing music out loud on trails can disrupt local wildlife. This can have a detrimental effect on the entire ecosystem and even lead to entire species being driven out of an area. </p><p>It impacts predators and prey in the wild alike, disrupting the food chain in the areas as well as breeding patterns. </p><div><blockquote><p>Activities such as finding desirable habitat and mates, avoiding predators, protecting young and establishing territories all depend on the acoustical environment.</p><p>The US National Park Service</p></blockquote></div><p>The <a href="https://www.nps.gov/subjects/sound/effects_wildlife.htm" target="_blank">United States government's National Park Service</a> states that sound plays an important role in ecosystems: "Activities such as finding desirable habitat and mates, avoiding predators, protecting young and establishing territories all depend on the acoustical environment."</p><p>Many speakers are marketed for use in the outdoors, and they do a good job at projecting sound when outside. If you're at the beach with friends or having a picnic they're great to have on-hand, but we should be mindful about where we use them. </p><p>Next time you're on the trail, keep the speaker back at camp and throw on a pair of headphones or open earbuds. Mother Nature will thank you for it.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-OarDyX"></div>                            </div>                            <script src="https://kwizly.com/embed/OarDyX.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/entertainment/netflix/netflixs-new-rom-com-with-jennifer-lopez-and-ted-lassos-brett-goldstein-is-now-streaming-and-its-got-all-the-charm-of-a-corporate-training-video"><strong>Netflix’s new rom-com with Jennifer Lopez and ‘Ted Lasso’s’ Brett Goldstein is now streaming — and it’s got all the charm of a corporate training video</strong></a></li><li><a href="https://www.tomsguide.com/home/i-found-this-usd10-ikea-tool-in-the-smart-home-section-thatll-help-you-keep-cool-without-breaking-the-budget"><strong>I found this $10 IKEA tool in the smart home section that'll help you keep cool without breaking the budget</strong></a></li><li><a href="https://www.tomsguide.com/wellness/fitness-trackers/i-spent-two-weeks-with-the-usd99-fitbit-air-here-are-my-3-reasons-to-buy-and-3-reasons-to-skip"><strong>I spent two weeks with the $99 Fitbit Air — here are my 3 reasons to buy (and 3 reasons to skip)</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I ditched my $54 JBL Go 5 to listen to music on the $49 8BitDo Retro Cube 2 speaker — and 8BitDo does something JBL doesn't ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-ditched-my-usd54-jbl-go-5-to-listen-to-music-on-the-usd49-8bitdo-retro-cube-2-speaker</link>
                                                                            <description>
                            <![CDATA[ I've been testing the 8BitDo Retro Cube 2 speaker and though it doesn't sound as full-bodied as the JBL Go 5, its cute looks and long battery life have won me over. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">PCFPgk6gdVziF4qUvtouDR</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/7SRu3iTvSprF9Aa6eM77HR-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 06 Jun 2026 05:00:00 +0000</pubDate>                                                                                                                                <updated>Wed, 10 Jun 2026 13:54:41 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/7SRu3iTvSprF9Aa6eM77HR-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:description>                                                            <media:text><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/7SRu3iTvSprF9Aa6eM77HR-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>It isn't often that I come across a product that makes me say, "Damn, I want to keep that on my desk forever." </p><p>That very thing happened last week, when I tested the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/8bitdo-retro-cube-2-review">8BitDo Retro Cube 2</a>, one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> around. I took one look at it and said, "Mine! Mine!" like the seagulls from Finding Nemo. </p><p>Up until that point, I was using the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5</a> to blast my favorite tunes, but now, I'm not sure I want to go back to the JBL — for a few good reasons.</p><div class="product"><a data-dimension112="fee2a85c-f324-43a7-a809-4ac3e432cd80" data-action="Deal Block" data-label="The 8BitDo Retro Cube 2 is the quirkiest speaker around, and that’s due to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine, though the bass could be more powerful." data-dimension48="The 8BitDo Retro Cube 2 is the quirkiest speaker around, and that’s due to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine, though the bass could be more powerful." data-dimension25="$49" href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:892px;"><p class="vanilla-image-block" style="padding-top:116.82%;"><img id="r5zUUMfK2PzaubVDbQfHCF" name="8BitDo-RetroCube2-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/r5zUUMfK2PzaubVDbQfHCF.jpg" mos="" align="middle" fullscreen="" width="892" height="1042" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The 8BitDo Retro Cube 2 is the quirkiest speaker around, and that’s due to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine, though the bass could be more powerful.<a class="view-deal button" href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow" data-dimension112="fee2a85c-f324-43a7-a809-4ac3e432cd80" data-action="Deal Block" data-label="The 8BitDo Retro Cube 2 is the quirkiest speaker around, and that’s due to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine, though the bass could be more powerful." data-dimension48="The 8BitDo Retro Cube 2 is the quirkiest speaker around, and that’s due to its NES-inspired design and D-pad-style controls. The speaker comes with a wireless charging dock with a slot to store the 2.4GHz dongle safely, and it boasts class-leading battery life of 30 hours. Crisp treble and a refined midrange make the speaker shine, though the bass could be more powerful." data-dimension25="$49">View Deal</a></p></div><p>JBL is arguably one of the biggest names in the audio sphere and when it comes to pure, full-bodied sound, the Go 5 upstages the Retro Cube 2. </p><p>8BitDo, on the other hand, is known for making retro-looking gaming and computing peripherals, and isn't a big player in the audio world. </p><p>So why do I still want to stick with the Retro Cube 2? Allow me to tell you why.</p><h2 id="a-10-10-nes-inspired-design">A 10/10 NES-inspired design</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="o2qE8emV5Evh444E2tQyq3" name="8bitDo_speaker_ 9.JPG" alt="8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/o2qE8emV5Evh444E2tQyq3.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>When it comes to design, the 8BitDo Retro Cube 2 is easily the winner. Sure, the JBL Go 5 looks sleek and attractive, and doesn't draw eyeballs, but does it have an NES-inspired design? D-pad-style controls? A charging dock that's good-looking <em>and </em>practical? No, but the Retro Cube 2 does.</p><div><blockquote><p>Sure, the JBL Go 5 looks sleek and attractive, but does it have an NES-inspired design? No, but the Retro Cube 2 does.</p></blockquote></div><p>The Retro Cube 2's design is inspired by the Nintendo Entertainment System (NES), and it comes in a combination of beige, red and black. It looks utterly fantastic, and it's the cutest, quirkiest speaker I've tested so far. If you have an <a href="https://www.tomsguide.com/computing/peripherals/8bitdo-retro-mechanical-keyboard-review" target="_blank">8BitDo Retro Mechanical Keyboard</a>, there's no better speaker to complement it.</p><p>Unlike any other speaker I've used, it comes with a charging dock so you can keep the speaker powered at all times. What's more, the charging dock has a slot for the Retro Cube 2's 2.4GHz dongle so that you don't lose it — neat!</p><div class="looped-video"><video class="lazyload-in-view lazyloading" data-src="https://cdn.mos.cms.futurecdn.net/JgfKhEpRZsTbrJGaE6QdK3/8BitDo%20%E2%80%94%20Startup%20sound.mp4" autoplay loop muted playsinline src="https://cdn.mos.cms.futurecdn.net/JgfKhEpRZsTbrJGaE6QdK3/8BitDo%20%E2%80%94%20Startup%20sound.mp4"></video></div><p>But perhaps my favorite stylistic choice on the Retro Cube 2 is its D-pad-like buttons to control playback. They give great tactile feedback when pressed, and given how much fun they are to press, it's like having a fidget toy and speaker all-in-one. </p><p>The best part? When you power on the speaker, it sings, “8BitDooooo.” Does the Go 5 do that? No way.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6938px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="fjPya8gWyNVCdRvgFLQGsh" name="8BitDo-Retro-Cube-2" alt="8BitDo Retro Cube 2 and 8BitDo Retro Mechanical Keyboard" src="https://cdn.mos.cms.futurecdn.net/fjPya8gWyNVCdRvgFLQGsh.jpg" mos="" align="middle" fullscreen="" width="6938" height="3903" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><p>The Go 5 naturally has a couple of aces up its sleeve — waterproofing and a rugged design, as well as better Bluetooth connectivity and support for advanced codecs. But given just how lovely the Retro Cube 2 looks, I'm OK living without them. </p><h2 id="all-day-listening-yes-please">All-day listening? Yes, please</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DrpQxnFVp8Lu8caQsiQUy3" name="8bitDo_speaker_ 4.JPG" alt="8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/DrpQxnFVp8Lu8caQsiQUy3.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>One of the key differences between the 8BitDo Retro Cube 2 and the JBL Go 5 is the battery life — and truth be told, it isn't even close. </p><p>The Go 5 is rated for just 10 hours, while the Retro Cube 2 achieves thrice that. At 30 hours, the Retro Cube 2 lasts a long, long time, and as it comes with a charging dock, you can keep it powered on at all times.</p><p>Question is, would you <em>want</em> to listen to music through the Retro Cube 2 all day long? Yes and no. Given that JBL dominates the audio space, it's not surprising that it sounds better than the Retro Cube 2 — but that doesn't mean the Retro Cube 2 is <em>all </em>bad. Treble is crisp and shiny without overpowering the rest of the soundstage, while the midrange is refined and tuned to make songs sound spacious.</p><p>The only real complaint I have with the Retro Cube 2's sound profile is the bass, which sounds muted. It's true that small speakers struggle to reproduce powerful bass, but the Go 5 does just that. The bass packs plenty of low-end impact on the Go 5, which feels non-existent on the Retro Cube 2. And as someone whose favorite bit of a song is the bass, the Retro Cube 2 left me wanting more. </p><p>You can read my in-depth sound quality analysis in my full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/8bitdo-retro-cube-2-review">8BitDo Retro Cube 2 review</a>.</p><h2 id="the-price-is-right">The price is right</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Bg7RCSuhiL75T76EpeJde3" name="8bitDo_speaker_ 1.JPG" alt="8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/Bg7RCSuhiL75T76EpeJde3.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Given everything I've said so far, I think it's pretty clear that I adore the 8BitDo Retro Cube 2. It looks fantastic, it sounds almost great, and it can comfortably last an all-day listening session. In fact, because of how beautiful it looks, the Retro Cube 2 has earned a permanent spot on my desk. Unlike most products that I promptly box up when I'm done testing them, the Retro Cube 2 is here to stay.</p><p>And the price is just right. The Retro Cube 2 is available for just <a href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">$49</a> / <a href="https://www.amazon.co.uk/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">£39 at Amazon</a>, making it an affordable and attractive speaker-cum-centerpiece package. As I write this, I'm listening to Lana Del Rey on the Retro Cube 2, and playing with those outstanding D-pad buttons. </p><p>Don't know about you, but I love my 🎶 8BitDooooo 🎶.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Odk2ZW"></div>                            </div>                            <script src="https://kwizly.com/embed/Odk2ZW.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/8bitdo-retro-cube-2-review">I’ve never seen a speaker as cute and quirky as the NES-inspired 8BitDo Retro Cube 2 — and it boasts surprisingly good sound for just $49</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-versus-jbl-go-4-face-off">I tested the JBL Go 5 vs JBL Go 4 budget Bluetooth speakers — and there’s a clear winner under $60</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/im-soundtracking-my-summer-with-the-usd54-jbl-go-5-its-one-of-the-best-budget-speakers-ive-ever-used">I’m soundtracking my summer with the $54 JBL Go 5 — it’s one of the best budget speakers I’ve ever used</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I’ve never seen a speaker as cute and quirky as the NES-inspired 8BitDo Retro Cube 2 — and it boasts surprisingly good sound for just $49 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/8bitdo-retro-cube-2-review</link>
                                                                            <description>
                            <![CDATA[ The 8BitDo Retro Cube 2 is an NES-inspired speaker with D-pad controls, and it boasts crisp treble and a refined midrange for $49. It has some flaws though. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">8ei5bCyM7HPHw2GcZGhR7K</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/eRckzAjnhpaftZk3Aif5uQ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 02 Jun 2026 09:38:42 +0000</pubDate>                                                                                                                                <updated>Tue, 09 Jun 2026 10:32:40 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/eRckzAjnhpaftZk3Aif5uQ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:description>                                                            <media:text><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/eRckzAjnhpaftZk3Aif5uQ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I’ve tested many of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> in my time, but most of them look either the same or they sport bland or uninventive design. Not the 8BitDo Retro Cube 2. It’s the cutest, quirkiest speaker you can buy today, and not for a lot of money as it costs just $49. An NES-inspired design and D-pad-style buttons make the Retro Cube 2 a joy to look at and use.</p><p>In addition to its simply fantastic design, the Retro Cube 2 boasts long battery life with up to 30 hours of playback time. It comes with a practical wireless charging dock too. Sound quality is great, with treble that shines and strong dynamics. However, given the speaker’s size and limited frequency response, the bass is a little lacking. It isn’t waterproof either, and its underbaked companion app doesn’t do it any favors.</p><p>Should you still buy it? Read my full 8BitDo Retro Cube 2 review to find out.</p><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-specs"><span>8BitDo Retro Cube 2 review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">$49</a> / <a href="https://www.amazon.co.uk/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">£39</a></p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>No IP rating</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3 with SBC, 2.4GHz, wired</p></td></tr><tr><td class="firstcol " ><p><strong>Multi-speaker connectivity</strong></p></td><td  ><p>No</p></td></tr><tr><td class="firstcol " ><p><strong>Multipoint</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Output power</strong></p></td><td  ><p>5W x 2</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response</strong></p></td><td  ><p>120Hz-15KHz</p></td></tr><tr><td class="firstcol " ><p><strong>Range</strong></p></td><td  ><p>Not specified</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>30 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>3.47 x 3.45 x 3.45 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>15.87oz (speaker); 3.06oz (charging dock)</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>N Edition (beige, red and black)</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-price-availability"><span>8BitDo Retro Cube 2 review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="eRckzAjnhpaftZk3Aif5uQ" name="8bitDo_speaker_ 4.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/eRckzAjnhpaftZk3Aif5uQ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The 8BitDo Retro Cube 2 is the successor to the first-gen speaker, which first came out in 2019. The 2026 iteration is priced similarly, and is available for <a href="https://www.amazon.com/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">$49</a> / <a href="https://www.amazon.co.uk/Portable-Bluetooth-Wireless-Charging-Connections/dp/B0G48LRFP4/" target="_blank" rel="nofollow">£39 at Amazon</a>. It’s available in one color only, at the time of writing: N Edition, which is a combination of beige, red and black.</p><p>If it’s a budget Bluetooth speaker you’re after, the Retro Cube 2 is perfect for you. It’s cheaper than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5 </a>($54) and the Tribit Stormbox Micro 3 ($64). It’s a little pricier than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a> ($39) and the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tozo-pe1-review">Tozo PE1</a> ($39) but it’s still in the same ballpark. So, why should you buy the Retro Cube 2 from a brand that isn’t as well-known for audio gear as it is for its retro-style peripherals? The design and long battery life, for starters, and we’ll get into the details next.</p><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-design"><span>8BitDo Retro Cube 2 review: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TFdpvvuvdeBc2KzxWgkD2R" name="8bitDo_speaker_ 3.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/TFdpvvuvdeBc2KzxWgkD2R.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I’ve tested a lot of Bluetooth speakers in my time, but I’ve never seen one as cute as the 8BitDo Retro Cube 2. Sporting a design inspired by the NES, the Retro Cube 2 fits right in with the brand’s other retro-style products. If you own the <a href="https://www.tomsguide.com/computing/peripherals/8bitdo-retro-mechanical-keyboard-review">8BitDo Retro Mechanical Keyboard</a> like I do, or the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/8bitdo-64-review">8BitDo 64</a> N64-styled gamepad, the Retro Cube 2 is the perfect accompaniment, thanks to its beige, red and black colors.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6938px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="fjPya8gWyNVCdRvgFLQGsh" name="8BitDo-Retro-Cube-2" alt="8BitDo Retro Cube 2 and 8BitDo Retro Mechanical Keyboard" src="https://cdn.mos.cms.futurecdn.net/fjPya8gWyNVCdRvgFLQGsh.jpg" mos="" align="middle" fullscreen="" width="6938" height="3903" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><p>The Retro Cube 2 is, as the name suggests, a cube. Four red speaker grilles are located on each face, and the top of the cube hosts the D-pad physical buttons, which I’ll talk about shortly. With subtle branding, the Retro Cube 2 is minimalist and good-looking, and is sure to draw eyeballs (in a good way). There’s no flashy RGB lighting, which I like, and the only bits that light up are the setting indicators on the top.</p><p>It’s quite small too, measuring just 3.47 x 3.45 x 3.45 inches. The Retro Cube 2 weighs 15.87oz so it’s a little heavier than the JBL Go 5 (8.16oz), but lighter than the Tribit StormBox Mini+ (19.2oz). A wireless charging dock is included in the box so you can keep the speaker powered at all times. Both the speaker and the dock host grippy rubbers to keep them from being unintentionally knocked about.</p><h2 id="weatherproofing-2">Weatherproofing</h2><p>8BitDo doesn’t specify an IP rating for the Retro Cube 2, so it isn’t waterproof or dustproof. Given that this speaker is designed for indoor use, this isn’t a massive drawback, but something to keep in mind before you choose to take it outdoors, or use it in the shower. For a rugged waterproof speaker, I’d recommend the JBL Go 5 (IP68) or the Tribit StormBox Mini+ (IPX7).</p><h2 id="controls-3">Controls</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="r2gbEECwzShYPvvdaXy7JR" name="8bitDo_speaker_.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/r2gbEECwzShYPvvdaXy7JR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The playback controls are in the form of an NES D-pad, and are unlike any other buttons you may have seen on other speakers. The four physical buttons enable you to adjust the volume, play/pause playback, and initiate Bluetooth pairing. All buttons give great tactile feedback when pressed.</p><div class="looped-video"><video class="lazyload-in-view lazyloading" data-src="https://cdn.mos.cms.futurecdn.net/JgfKhEpRZsTbrJGaE6QdK3/8BitDo%20%E2%80%94%20Startup%20sound.mp4" autoplay loop muted playsinline src="https://cdn.mos.cms.futurecdn.net/JgfKhEpRZsTbrJGaE6QdK3/8BitDo%20%E2%80%94%20Startup%20sound.mp4"></video></div><p>To add to the speaker’s quirkiness, when you press the power button to, well, power on the speaker, the speaker sings, “8BitDooooo.” 10/10, no notes.</p><h2 id="connectivity-3">Connectivity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="n6mt4TFyBcYwpxjnHpbsrQ" name="8bitDo_speaker_ 5.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/n6mt4TFyBcYwpxjnHpbsrQ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Retro Cube 2 utilizes Bluetooth 5.3 with support for the standard SBC codec. There’s no AAC or LC3, like on the JBL Go 5. You do get multipoint connectivity, though, so you can connect two devices simultaneously. I did this with my <a href="https://www.tomsguide.com/phones/google-pixel-phones/google-pixel-10-pro-xl-review">Google Pixel 10 Pro XL</a> and my <a href="https://www.tomsguide.com/reviews/macbook-air-2022-m2">MacBook Air M2</a> and it worked seamlessly.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="XGoAGM6nt2ZLWBYL8aAFtQ" name="8bitDo_speaker_ 6.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/XGoAGM6nt2ZLWBYL8aAFtQ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>In addition to Bluetooth, the Retro Cube 2 comes with a 2.4GHz dongle for virtually lag-free audio in games and music. The dongle can be stored in a slot located on the charging dock’s underside, which is a neat feature as it keeps it from getting lost. There’s wired playback too, via the USB-C port located around the back.</p><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-sound-quality"><span>8BitDo Retro Cube 2 review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4393LYVEzQ2UYQu46fH6BR" name="8bitDo_speaker_ 8.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/4393LYVEzQ2UYQu46fH6BR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you want a speaker to soundtrack your workday, gaming session, or an intimate dinner party, the 8BitDo Retro Cube 2 is up to the challenge. It has a power output of 10W (5W x 2) and covers a frequency response range of 125Hz to 15KHz. Given that it goes down to just 125Hz, the sub-bass and bass in general are a little lacking, but I’ll talk about that later. Good things first.</p><p>To test the Retro Cube 2, I listened to my usual selection of testing songs on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, the <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service</a> for hi-res, over Bluetooth. I kicked things off with ‘<a href="https://open.qobuz.com/track/80418830" target="_blank" rel="nofollow">One Inch Punch</a>’ by Yin Yin. This track highlighted the Retro Cube 2’s treble clarity, as the song’s bright surf-guitar riffs, crisp hi-hats and intricate percussion came through with plenty of energy and definition. The track sounded lively and the guitar notes cut cleanly through the mix, while percussion retained its texture without becoming harsh.</p><p>The Retro Cube 2 features a surprisingly capable midrange too. Lana Del Rey’s vocals in ‘<a href="https://open.qobuz.com/track/203578478" target="_blank" rel="nofollow">Taco Truck x VB</a>’ sat front and centre, sounding clear, intimate and well-defined which allowed the emotional nuances in her performance to come through effortlessly. The guitars blended smoothly without becoming congested, and the Retro Cube 2 lent the midrange elements a natural warmth that flattered the song’s laid-back, hazy production style.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="7SRu3iTvSprF9Aa6eM77HR" name="8bitDo_speaker_ 1.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/7SRu3iTvSprF9Aa6eM77HR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>But the only disappointing bit about the Retro Cube 2 is its limited bass capabilities — something commonplace in small speakers. I played ‘<a href="https://open.qobuz.com/track/121923140" target="_blank" rel="nofollow">No Chances</a>’ by Twenty One Pilots to test the speaker’s bass extension. While the track’s ominous low-end pulse and deep synth bass were present, they lacked the weight and physical impact that lend the song much of its tension — something you won’t experience when listening to it through the JBL Go 5. The song’s cinematic foundation, then, felt noticeably reduced, and while the kickdrums had definition, they didn’t hit with the chest-thumping force the song demands.</p><p>Overall, the Retro Cube 2 performs well but doesn’t provide a sound as full as the JBL Go 5, so if you want powerful bass, you may want to consider the JBL instead. But if cute looks matter more to you, then the Retro Cube 2 is a no-brainer.</p><p><em>Listen along to my review with the 8BitDo Retro Cube 2 testing playlist:</em></p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/64843841?zone=GB-en"></iframe><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-app"><span>8BitDo Retro Cube 2 review: App</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="LK6UhmxAggp5BRfE5BuGFR" name="8bitDo_speaker_ 7.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/LK6UhmxAggp5BRfE5BuGFR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The 8BitDo Retro Cube 2 doesn’t have a mobile companion app, so you can’t customize the speaker on the fly. Well, you can’t customize the speaker full stop. While the Retro Cube 2 is compatible with the <a href="https://app.8bitdo.com/Ultimate-Software-V2/" target="_blank" rel="nofollow">8BitDo Ultimate Software V2</a> macOS and Windows app, the only thing you can do is update the speaker’s firmware.</p><p>This means that there’s no custom EQ or way to remap the buttons. If you want customizable EQ, I’d recommend spending a little extra on the JBL Go 5, or getting the cheaper Tribit StormBox Mini+.</p><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-battery-life"><span>8BitDo Retro Cube 2 review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="T2W7qBf7gfSdGfahHXYZ7R" name="8bitDo_speaker_ 9.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/T2W7qBf7gfSdGfahHXYZ7R.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>One of the 8BitDo Retro Cube 2’s biggest selling points is its long battery life, which is class-leading. 8BitDo says that the speaker can last up to 30 hours, and can go from zero to 100% in three hours. In my testing, the Retro Cube 2 ran out of battery around the 29th hour mark when it was playing at 50% volume.</p><p>The Retro Cube 2 outclasses most other speakers in its weight class. The JBL Go 5 offers a maximum playtime of 10 hours, while the Tribit StormBox Mini+ can last up to 12 hours. The Tozo PE1 has a rated battery life of 32 hours at low volume, and we found that it drained really quickly at high volumes. Given that, the Retro Cube 2 is your best option in the battery life department.</p><p>Unlike any other tiny Bluetooth speaker I’ve tested, the Retro Cube 2 comes with a wireless charging dock to keep it powered at all times.</p><h2 class="article-body__section" id="section-8bitdo-retro-cube-2-review-verdict"><span>8BitDo Retro Cube 2 review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9Xq5jy2dZnQHMxMFUpEr8S" name="8bitDo_speaker_ 10.JPG" alt="A beige, red and black 8BitDo Retro Cube 2 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/9Xq5jy2dZnQHMxMFUpEr8S.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Few Bluetooth speakers are as attractive as the 8BitDo Retro Cube 2. This cute little thing sports an NES-inspired design that’s sure to impress retro gamers. Its D-pad-style buttons not only give good tactile feedback when pressed, but they add to the Retro Cube 2’s charm too. Throw in 30 hours of battery life and a wireless charging dock with dongle storage and you’ve got yourself a winner.</p><p>But how does it sound? The Retro Cube 2 boasts great sound dynamics with the ability to make the treble sparkle. However, the bass is a little lacking, given that the speaker doesn’t have a wide frequency response range. It doesn’t have a custom EQ either, and it isn’t waterproof.</p><p>Should those drawbacks stop you from getting the Retro Cube 2? Depends on what you’re after. If you want a full-bodied sound, the JBL Go 5 is clearly the superior option. But if you want a $49 speaker that makes for a great addition to your setup, or as a coffee table centerpiece, the Retro Cube 2 is sure to please you. Its retro aesthetics have won me over, and it's become a permanent fixture on my desk. I’m vibing to the “8BitDoooo” startup sound.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ This affordable, pocket-sized Bluetooth speaker is on sale for less than $25 — here's 11 more speaker deals to get the party going ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/this-affordable-pocket-sized-bluetooth-speaker-is-on-sale-for-less-than-usd25-heres-11-more-speaker-deals-to-get-the-party-going</link>
                                                                            <description>
                            <![CDATA[ Some of the best speakers we've tested are on sale this summer — check out these deals to get the biggest sound quality at tiny prices. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">kmrrfuyWk3BY9aUcQoJCw4</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/w76fCuYEJvmP6PEU5C2BrH-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 29 May 2026 11:25:39 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ millie.daviswilliams@futurenet.com (Millie Davis-Williams) ]]></author>                    <dc:creator><![CDATA[ Millie Davis-Williams ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/WU6pa7hKuxs5ScCoqcXYWA.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Millie is a Deals Editor at Tom&#039;s Guide specializing in tech deals content. Based in London, Millie has spent a lifetime stubbornly refusing to pay full price on any possible purchase. She has years of searching for the best discounts on the latest and greatest phones, TVs and gadgets under her belt, and knows how to sort the best deals from the rest. Helping readers save on the products they want is her mission, whether it’s an Apple Watch or a new tablet.&lt;/p&gt;&lt;p&gt;Since working at Tom’s Guide, Millie has covered retail events like Prime Day, Black Friday and Cyber Monday extensively, meaning she knows the products readers are looking for and the best times of year to hit “purchase.”&lt;/p&gt;&lt;p&gt;When she’s not looking for discounts, Millie covers news and writes how-to articles about everything from phones, streaming devices, and headphones to apps and video games.&lt;/p&gt;&lt;p&gt;In her spare time, Millie enjoys reading, gaming on her Nintendo Switch and creating digital art. She’s also a fan of watching Disney movies and collecting plush (the latter having totally taken over her bedroom.)&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/w76fCuYEJvmP6PEU5C2BrH-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit PocketGo Bluetooth Speaker]]></media:description>                                                            <media:text><![CDATA[Tribit PocketGo Bluetooth Speaker]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit PocketGo Bluetooth Speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/w76fCuYEJvmP6PEU5C2BrH-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Summer is here, and that means outdoor parties, picnics, hikes, camping and road trips. Everything in summer is way more fun with your favorite tunes pumping, so I've been searching for the best Bluetooth speaker deals to get you amazing sound quality without breaking the bank.</p><p>Right now you can get the <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow">Tribit PocketGo for $24 at Amazon</a>. It's the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> on a budget — my colleagues were shocked at how amazing its sound quality is, and it truly outperforms its small size and small price tag. Make sure to snag one while you can.</p><p>There are lots more Bluetooth speaker deals out there from top audio brands, so keep scrolling to see my favorites. I also recommend checking out our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a>.</p><h2 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h2><ul><li><a href="https://www.amazon.com/b?_encoding=UTF8&node=7073956011" target="_blank" rel="nofollow"><strong>shop Bluetooth speaker deals at Amazon</strong></a></li><li><strong>Tribit PocketGo: </strong><a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><strong>was $29 now $24</strong></a></li><li><strong>Ultimate Ears WonderBoom 4: </strong><a href="https://www.amazon.com/dp/B0BRXJVG1S" target="_blank" rel="nofollow"><strong>was $99 now $51</strong></a></li><li><strong>Soundcore Boom 2: </strong><a href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><strong>was $139 now $89</strong></a></li><li><strong>JBL Flip 6: </strong><a href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8/ref" target="_blank" rel="nofollow"><strong>was $129 now $89</strong></a></li><li><strong>Bose SoundLink Micro Portable (2nd Gen): </strong><a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow"><strong>was $129 now $99</strong></a></li><li><strong>Marshall Stanmore III: </strong><a href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTFCR59" target="_blank" rel="nofollow"><strong>was $399 now $299</strong></a><strong> </strong></li></ul><h2 class="article-body__section" id="section-best-bluetooth-speaker-deals"><span>Best Bluetooth speaker deals</span></h2><div class="product"><a data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="XnqELzjemVWDKqXxoESeBh" name="tribit-pocketgo-bluetooth-shower-speaker-e7119067-af9e-4c09-9feb-6f1f593c89d6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XnqELzjemVWDKqXxoESeBh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review" data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24">Tribit PocketGo</a> will be your new best friend. For less than $30, this Bluetooth speaker packs one heck of a punch in the sound department. On top of that, it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for long hikes in unpredictable weather. And I do mean <em>long</em> hikes because the speaker has a total battery life of 20 hours, making it ideal for a weekend camping trip. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24">View Deal</a></p></div><div class="product"><a data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1425px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="D7QYGUpe98kCsZkVddg4oV" name="Ultimate Ears Wonderboom 4.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/D7QYGUpe98kCsZkVddg4oV.jpg" mos="" align="middle" fullscreen="" width="1425" height="1425" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The mighty and portable Wonderboom 4 is a great outdoor speaker that goes louder than it has any right to. In our <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review" data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51">Ultimate Ears WonderBoom 4 review</a>, our reviewer loved its compact size, very good 16-hour battery life and slick rugged looks. It's IP67 water and dust-resistant as well, so you can really take it anywhere to listen to your tunes.<a class="view-deal button" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow" data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$51">View Deal</a></p></div><div class="product"><a data-dimension112="3e744887-8eb6-40e9-ad93-f3354cea8f2d" data-action="Deal Block" data-label="We rank the StormBox Micro 2 as the best Bluetooth speaker for travel, and this new iteration looks like more of a good thing. I just got my hands on this one myself, and I'm already loving the magnetic design and carry strap — it's extremely easy to take along or set up on a magnetic surface." data-dimension48="We rank the StormBox Micro 2 as the best Bluetooth speaker for travel, and this new iteration looks like more of a good thing. I just got my hands on this one myself, and I'm already loving the magnetic design and carry strap — it's extremely easy to take along or set up on a magnetic surface." data-dimension25="$59" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1110px;"><p class="vanilla-image-block" style="padding-top:118.65%;"><img id="UYAz4ytBrnKLyZwUopY4fS" name="StormBox Micro 3" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/UYAz4ytBrnKLyZwUopY4fS.jpg" mos="" align="middle" fullscreen="" width="1110" height="1317" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>We rank the StormBox Micro 2 as the best Bluetooth speaker for travel, and this new iteration looks like more of a good thing. I just got my hands on this one myself, and I'm already loving the magnetic design and carry strap — it's extremely easy to take along or set up on a magnetic surface.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow" data-dimension112="3e744887-8eb6-40e9-ad93-f3354cea8f2d" data-action="Deal Block" data-label="We rank the StormBox Micro 2 as the best Bluetooth speaker for travel, and this new iteration looks like more of a good thing. I just got my hands on this one myself, and I'm already loving the magnetic design and carry strap — it's extremely easy to take along or set up on a magnetic surface." data-dimension48="We rank the StormBox Micro 2 as the best Bluetooth speaker for travel, and this new iteration looks like more of a good thing. I just got my hands on this one myself, and I'm already loving the magnetic design and carry strap — it's extremely easy to take along or set up on a magnetic surface." data-dimension25="$59">View Deal</a></p></div><div class="product"><a data-dimension112="a4801986-08e5-4cb3-b7c9-996fa5055660" data-action="Deal Block" data-label="A speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="A speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$89" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3CvgYRTFMbxneUZcepKkae" name="soundcore boom 2" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3CvgYRTFMbxneUZcepKkae.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>A speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go <em>loud</em>. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere. <a class="view-deal button" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow" data-dimension112="a4801986-08e5-4cb3-b7c9-996fa5055660" data-action="Deal Block" data-label="A speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="A speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="485932c0-c3ef-4154-86ee-5eeeefaa49e9" data-action="Deal Block" data-label="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension48="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension25="$89" href="https://www.amazon.com/Marshall-Willen-Bluetooth-Portable-Speaker/dp/B0DD7T8H2Q" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CUupDdwp3iFPpTNoLMAwEg" name="marshall-willen-ii-portable-bluetooth-sp-2bd48523-b998-4c85-b830-a731963cc40d.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CUupDdwp3iFPpTNoLMAwEg.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup.<a class="view-deal button" href="https://www.amazon.com/Marshall-Willen-Bluetooth-Portable-Speaker/dp/B0DD7T8H2Q" target="_blank" rel="nofollow" data-dimension112="485932c0-c3ef-4154-86ee-5eeeefaa49e9" data-action="Deal Block" data-label="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension48="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="cf0750f0-bdd8-47b5-959d-4238241380b0" data-action="Deal Block" data-label="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too." data-dimension48="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too." data-dimension25="$99" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1105px;"><p class="vanilla-image-block" style="padding-top:110.05%;"><img id="W9bhTKNwnzv3HgRUn6A2sc" name="SoundLink Micro Portable Bluetooth Speaker (2nd Gen)" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/W9bhTKNwnzv3HgRUn6A2sc.jpg" mos="" align="middle" fullscreen="" width="1105" height="1216" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow" data-dimension112="cf0750f0-bdd8-47b5-959d-4238241380b0" data-action="Deal Block" data-label="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too." data-dimension48="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too." data-dimension25="$99">View Deal</a></p></div><div class="product"><a data-dimension112="313957f5-fbf2-4fcc-9aa0-1464b9ab102d" data-action="Deal Block" data-label="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$89" href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:120.00%;"><img id="33AJemCSzK8fNYEhkUfBtm" name="JBL Flip 6" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/33AJemCSzK8fNYEhkUfBtm.jpg" mos="" align="middle" fullscreen="" width="1000" height="1200" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening. <a class="view-deal button" href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8" target="_blank" rel="nofollow" data-dimension112="313957f5-fbf2-4fcc-9aa0-1464b9ab102d" data-action="Deal Block" data-label="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. It's now on sale and an awesome deal for this pocket-sized 30W speaker. It's IP67 rated and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="93f486a2-a5f2-431c-902c-e99df9039999" data-action="Deal Block" data-label="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension48="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension25="$159" href="https://www.amazon.com/JBL-Charge-Waterproof-Drop-Proof-Built/dp/B0G7D9BLYJ" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:60.93%;"><img id="fAV3y9WMvrAFWQKezHyaAh" name="JBL Charge 6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fAV3y9WMvrAFWQKezHyaAh.jpg" mos="" align="middle" fullscreen="" width="1500" height="914" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want.<a class="view-deal button" href="https://www.amazon.com/JBL-Charge-Waterproof-Drop-Proof-Built/dp/B0G7D9BLYJ" target="_blank" rel="nofollow" data-dimension112="93f486a2-a5f2-431c-902c-e99df9039999" data-action="Deal Block" data-label="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension48="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension25="$159">View Deal</a></p></div><div class="product"><a data-dimension112="6f6766cf-33fa-4aff-bf2d-1e773748a447" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market." data-dimension25="$199" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Cream/dp/B0BBYF2SXX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="VK72LAYkKKEKEWGPQxGoBn" name="marshall-acton-iii-bluetooth-home-speake-9c29b8fe-0398-481f-b43e-eb4a003dadde.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VK72LAYkKKEKEWGPQxGoBn.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market.<a class="view-deal button" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Cream/dp/B0BBYF2SXX" target="_blank" rel="nofollow" data-dimension112="6f6766cf-33fa-4aff-bf2d-1e773748a447" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market." data-dimension25="$199">View Deal</a></p></div><div class="product"><a data-dimension112="4cdca56d-f77f-4b47-b824-65ab24c474f3" data-action="Deal Block" data-label="JBL Boombox 3 review" data-dimension48="JBL Boombox 3 review" data-dimension25="$299" href="https://www.amazon.com/JBL-Boombox-Waterproof-PartyBoost-eco-Friendly/dp/B09YDS8BHK" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1562px;"><p class="vanilla-image-block" style="padding-top:56.27%;"><img id="mz3Lg9DhD3d25zqFxXtyCS" name="JBL Boombox 3 (1).jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/mz3Lg9DhD3d25zqFxXtyCS.jpg" mos="" align="middle" fullscreen="" width="1562" height="879" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>JBL's awesome Boombox range is like the Xtreme line on steroids. In our 4-star <a href="https://www.tomsguide.com/reviews/jbl-boombox-3" data-dimension112="4cdca56d-f77f-4b47-b824-65ab24c474f3" data-action="Deal Block" data-label="JBL Boombox 3 review" data-dimension48="JBL Boombox 3 review" data-dimension25="$299">JBL Boombox 3 review</a>, we loved the booming bass and the Boombox 3's ability to fill a large outdoor area. Although it's a heavy speaker, the rugged design and all-day (24 hour) battery life means it'll keep the party going regardless. It'll play even in torrential rain — it's IP67 rated.<a class="view-deal button" href="https://www.amazon.com/JBL-Boombox-Waterproof-PartyBoost-eco-Friendly/dp/B09YDS8BHK" target="_blank" rel="nofollow" data-dimension112="4cdca56d-f77f-4b47-b824-65ab24c474f3" data-action="Deal Block" data-label="JBL Boombox 3 review" data-dimension48="JBL Boombox 3 review" data-dimension25="$299">View Deal</a></p></div><div class="product"><a data-dimension112="127125be-37ad-40b3-a26e-cd8cc5eaa6e2" data-action="Deal Block" data-label="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension48="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension25="$299" href="https://www.amazon.com/dp/B09HTFCR59" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wYnAg4Aq77FqRs4Sxa3xn7" name="marshall stanmore iii" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wYnAg4Aq77FqRs4Sxa3xn7.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire. <a class="view-deal button" href="https://www.amazon.com/dp/B09HTFCR59" target="_blank" rel="nofollow" data-dimension112="127125be-37ad-40b3-a26e-cd8cc5eaa6e2" data-action="Deal Block" data-label="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension48="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension25="$299">View Deal</a></p></div><div class="product"><a data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349" href="https://www.amazon.com/dp/B0F967JT5Y" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1509px;"><p class="vanilla-image-block" style="padding-top:99.34%;"><img id="h3j5SdPPY2co2Kf2LhGvk3" name="Marshall Kilburn III.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/h3j5SdPPY2co2Kf2LhGvk3.jpg" mos="" align="middle" fullscreen="" width="1509" height="1499" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The epic-looking <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review" data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">Marshall Kilburn III</a> is more than just a pretty face — it also sounds amazing too. The battery life is extremely impressive, and the on-device tone controls make keeping the music going easier than anything else. It also, you know, looks really cool. We currently rank it as the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> you can buy.<a class="view-deal button" href="https://www.amazon.com/dp/B0F967JT5Y" target="_blank" rel="nofollow" data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">View Deal</a></p></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living, and these are the 3 I'll be using all summer long — and they start at just $20 on sale ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-these-are-the-3-ill-be-using-all-summer-long-and-theyre-all-under-usd140</link>
                                                                            <description>
                            <![CDATA[ Whether you want ground-shaking bass or impressive sound clarity, these are the speakers I recommend for outdoor listening this summer. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">BHAtTqEANQSnhXmHhJBm2X</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/FhkwdSdHD8nTBw8U5o3AiZ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 24 May 2026 06:15:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/FhkwdSdHD8nTBw8U5o3AiZ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Tribit PocketGo speaker in black photographed on a blue background. ]]></media:description>                                                            <media:text><![CDATA[The Tribit PocketGo speaker in black photographed on a blue background. ]]></media:text>
                                <media:title type="plain"><![CDATA[The Tribit PocketGo speaker in black photographed on a blue background. ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/FhkwdSdHD8nTBw8U5o3AiZ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I test audio gear for a living, and that means I get my hands on some of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> on the market. But in the hours I spend testing these speakers, there are only a few that I keep going back to. </p><p>And these top choice speakers are the proof you need that you don't need to spend big bucks to get awesome sound because they're all on sale. In fact, the priciest one is just $111. </p><p>All of these speakers have impressive battery life, durability protection for the outdoors, and most importantly, impressive sound. So without further ado, these are the speakers I'll be reaching for all summer long. </p><ul><li><strong>Tribit PocketGo: </strong><a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><strong>was $29 now $19 at Amazon</strong></a></li><li><strong>Marshall Willen II: </strong><a href="https://www.amazon.com/Marshall-Willen-Bluetooth-Portable-Speaker/dp/B0DD7T8H2Q" target="_blank" rel="nofollow"><strong>was $129 now $89 at Amazon</strong></a><strong></strong></li><li><strong>Tribit Stormbox Lava: </strong><a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" target="_blank" rel="nofollow"><strong>was $139 now $111 at Amazon</strong></a></li></ul><h2 id="tribit-pocketgo">Tribit PocketGo</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="BzZgxLUemS3J7E73zpJd3a" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/BzZgxLUemS3J7E73zpJd3a.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a> is a speaker I use almost daily, and it comes absolutely everywhere with me. In fact, it's coming on vacation with me next week so I can listen to my favorite tracks by the pool. And I don't even have to worry about it getting wet because it has an impressive durability rating of IP68. </p><p>This sub-$30 speaker is nothing short of impressive. It sounds like it should be triple its size when it measures just 4.3 x 3.2 x 1.7 inches. But the 20 hours of battery life are what really win me over. Even at the highest volumes, the battery lasts me days at a time, although this will depend on your own listening habits. </p><div class="product"><a data-dimension112="ca21c58f-b788-4737-a1f4-f1a955d9a872" data-action="Deal Block" data-label="The Tribit PocketGo is a rugged speaker with an IP68 waterproof rating, making it ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="The Tribit PocketGo is a rugged speaker with an IP68 waterproof rating, making it ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$19" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="yFUH5DvQg4Bso6HJiAXHdM" name="tribit-pocketgo-bluetooth-shower-speaker-d7445412-d4ef-4b07-979b-7089fe237b0e.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/yFUH5DvQg4Bso6HJiAXHdM.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit PocketGo is a rugged speaker with an IP68 waterproof rating, making it ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes.<a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="ca21c58f-b788-4737-a1f4-f1a955d9a872" data-action="Deal Block" data-label="The Tribit PocketGo is a rugged speaker with an IP68 waterproof rating, making it ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="The Tribit PocketGo is a rugged speaker with an IP68 waterproof rating, making it ideal for adventures, along with military-grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$19">View Deal</a></p></div><h2 id="marshall-willen-ii">Marshall Willen II</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="dgijJ7akaPXRoD3qRDA2Go" name="Marshall Willen II" alt="Marshall Willen II" src="https://cdn.mos.cms.futurecdn.net/dgijJ7akaPXRoD3qRDA2Go.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>This is the speaker I get out when I want to show off a little. The <a href="https://www.tomsguide.com/audio/marshall-willen-ii-review-rugged-rockin-fun">Marshall Willen II</a> is the sleek answer to the world of portable Bluetooth speakers, and it's not hard to see why. Just look at it. </p><p>It's compact, measuring 3.9 x 3.9 x 1.7 inches, and is as light as a feather, weighing just 0.79 lbs. It's has 17 hours of battery to soundtrack your whole day outdoors without needing to worry about a charger, and the durability rating of IP67 means that the speaker can withstand rain or shine. </p><div class="product"><a data-dimension112="ebde716e-cea6-4f2b-bf87-0ca2c308112c" data-action="Deal Block" data-label="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension48="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension25="$89" href="https://www.amazon.com/Marshall-Willen-Bluetooth-Portable-Speaker/dp/B0DD7T8H2Q" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CUupDdwp3iFPpTNoLMAwEg" name="marshall-willen-ii-portable-bluetooth-sp-2bd48523-b998-4c85-b830-a731963cc40d.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CUupDdwp3iFPpTNoLMAwEg.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup.<a class="view-deal button" href="https://www.amazon.com/Marshall-Willen-Bluetooth-Portable-Speaker/dp/B0DD7T8H2Q" target="_blank" rel="nofollow" data-dimension112="ebde716e-cea6-4f2b-bf87-0ca2c308112c" data-action="Deal Block" data-label="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension48="The Willen II is a tiny powerhouse of a speaker that packs quality sound and good battery life into a compact package. It'll last for 17 hours, which is longer than some of the larger competitors. This little speaker is well worth the pickup." data-dimension25="$89">View Deal</a></p></div><h2 id="tribit-stormbox-lava">Tribit Stormbox Lava</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RiKpvQVuXrCbdsWTcSLvm" name="Tribit StormBox Lava Bluetooth Speaker" alt="Tribit StormBox Lava Bluetooth Speaker photographed in front of a blue background." src="https://cdn.mos.cms.futurecdn.net/RiKpvQVuXrCbdsWTcSLvm.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Another choice from Tribit, but it's for good reason — the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit Stormbox Lava</a> provides incredible ground-shaking bass. This is the speaker that I used almost every single day in my backyard last summer, and it was the perfect addition to every barbecue, bonfire and sunbathing session. </p><p>The 24 hours of battery keep me company all day long, and just like the PocketGo, it's waterproof and dustproof, so there's no need to worry about any spontaneous rain. You can also use stereo pairing with this speaker, but you'll need to purchase two of them.</p><div class="product"><a data-dimension112="44486f2e-5f27-48e3-be22-1ba9709591d8" data-action="Deal Block" data-label="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but still packs a punch. The BassX setting really brings out the bass in your tunes.. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension48="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but still packs a punch. The BassX setting really brings out the bass in your tunes.. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension25="$111" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="vbCmBfAuxEssM9rj67FzbM" name="tribit-stormbox-lava-portable-bluetooth--034b079e-af40-4a16-bcae-8001aa3bff5f.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/vbCmBfAuxEssM9rj67FzbM.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but still packs a punch. The BassX setting really brings out the bass in your tunes.. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" target="_blank" rel="nofollow" data-dimension112="44486f2e-5f27-48e3-be22-1ba9709591d8" data-action="Deal Block" data-label="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but still packs a punch. The BassX setting really brings out the bass in your tunes.. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension48="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but still packs a punch. The BassX setting really brings out the bass in your tunes.. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension25="$111">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/wellness/workouts/stop-doing-100s-of-sit-ups-im-a-personal-trainer-and-i-use-bear-plank-openers-to-build-strong-abs-and-hips-instead"><strong>We know that core workouts build strong ab muscles, but what move should you start with for strength and stability after 50?</strong></a></li><li><a href="https://www.tomsguide.com/wellness/smartwatches/i-walked-5-500-steps-with-the-apple-watch-se-3-vs-garmin-forerunner-70-and-this-smartwatch-won"><strong>I walked 5,500 steps with the Apple Watch SE 3 vs Garmin Forerunner 70 — and the results surprised me</strong></a></li><li><a href="https://www.tomsguide.com/tvs/oled-tvs/we-just-tested-the-lg-b6-oled-and-its-actually-better-than-the-c6-in-this-one-area"><strong>We just lab tested the LG B6 OLED — here's how it stacks up to the LG C6</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ This Fender Bluetooth speaker doubles as an amp for your guitar — and it’s just $300 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/this-fender-bluetooth-speaker-doubles-as-an-amp-for-your-guitar-and-its-just-usd300</link>
                                                                            <description>
                            <![CDATA[ This new Bluetooth speaker from Fender allows you to take your music — and guitars — anywhere and everywhere you want to go. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">GjCgUmrpbgCsVJikP2hDPJ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/TwWSnVyjBtMdHvSjxRQ7r6-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 23 May 2026 07:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ Nick.Pino@futurenet.com (Nick Pino) ]]></author>                    <dc:creator><![CDATA[ Nick Pino ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/7xnnEdyK5eEbDVbS5pYB54.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nick Pino heads up the TV and AV verticals at Tom&#039;s Guide and covers everything from OLED TVs to the latest wireless headphones. He&#039;s a Level 1 Certified THX Home Theater Professional, and has attended classes on TV and audio calibration. On Tom&#039;s Guide, he looks after some of the site&#039;s important buying guides like the best TVs, best OLED TVs, best 4K TVs, so most of his day is spent watching and evaluating new screens from LG, Samsung, Sony, Hisense, TCL and Vizio. (And yes, he knows how lucky he is to say that.) He was formerly the Senior Editor, TV and AV at TechRadar (Tom&#039;s Guide&#039;s sister site) and has previously written for GamesRadar, Official Xbox Magazine, PC Gamer and other outlets over the last decade. He got his start on Best Buy&#039;s official video game magazine, @GAMER, for whom he attended his first E3 in 2013. He&#039;s served as a judge for CES&#039; prestigious Innovation Awards and has attended the tech conference in Las Vegas since 2014. He has a computer science degree from the University at Buffalo and still resides in the Buffalo area. (Go Bills!) Not sure which TV you should buy? Drop him an email or tweet him on Twitter and he can help you out.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/TwWSnVyjBtMdHvSjxRQ7r6-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A Fender Audio ELIE 6 in a small room.]]></media:description>                                                            <media:text><![CDATA[A Fender Audio ELIE 6 in a small room.]]></media:text>
                                <media:title type="plain"><![CDATA[A Fender Audio ELIE 6 in a small room.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/TwWSnVyjBtMdHvSjxRQ7r6-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Marshall might be making waves with its audio products like the <a href="https://www.tomsguide.com/audio/headphones/marshall-milton-anc-review"><u>Marshall Milton ANC</u></a>, but it’s not the only instrument maker-turned-electronics manufacturer in town — the Fender brand also has a new suite of Bluetooth speakers that allows you to take your music (and guitars) anywhere and everywhere you want to go. </p><p>The most affordable entry in the two-piece ensemble is the ELIE 6, a $299 portable Bluetooth speaker that was developed by the Fender Audio team. It features a quarter-inch XLR port for music instruments, which I’ve been using with my Ibanez bass.</p><p>Is $300 a bit too much to spend on a <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">portable Bluetooth speaker</a> when you can get louder, more competent models like the LG Xboom Grab and Ultimate Ears Boom 4 for half the price? Yeah, probably. But having a portable speaker that doubles as an amp is certainly handy for vagabonding musicians looking to take their music on the road.</p><div class="product"><a data-dimension112="7b888c9a-5729-4ac2-9b9d-a7646e22e150" data-action="Deal Block" data-label="Need a portable amp that doesn't break your back every time you pick it up? Meet the Fender Audio ELIE 6. This 4-pound speaker delivers strong mids and treble when connected to both Bluetooth devices and music instruments alike. It's IP54 dust protected and water resistant, comes in both Skyscraper Black and Olympic White, and sports an 18-hour battery life. For serenades at the park and impromptu shows for friends, it does the trick." data-dimension48="Need a portable amp that doesn't break your back every time you pick it up? Meet the Fender Audio ELIE 6. This 4-pound speaker delivers strong mids and treble when connected to both Bluetooth devices and music instruments alike. It's IP54 dust protected and water resistant, comes in both Skyscraper Black and Olympic White, and sports an 18-hour battery life. For serenades at the park and impromptu shows for friends, it does the trick." data-dimension25="$299" href="https://fenderaudio.com/products/elie-06/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:436px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="Fzsfkka34wStY8rzH5T4uN" name="Fender ELIE 6 SQUARE" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/Fzsfkka34wStY8rzH5T4uN.jpg" mos="" align="middle" fullscreen="" width="436" height="436" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Need a portable amp that doesn't break your back every time you pick it up? Meet the Fender Audio ELIE 6. This 4-pound speaker delivers strong mids and treble when connected to both Bluetooth devices and music instruments alike. It's IP54 dust protected and water resistant, comes in both Skyscraper Black and Olympic White, and sports an 18-hour battery life. For serenades at the park and impromptu shows for friends, it does the trick.<a class="view-deal button" href="https://fenderaudio.com/products/elie-06/" target="_blank" rel="nofollow" data-dimension112="7b888c9a-5729-4ac2-9b9d-a7646e22e150" data-action="Deal Block" data-label="Need a portable amp that doesn't break your back every time you pick it up? Meet the Fender Audio ELIE 6. This 4-pound speaker delivers strong mids and treble when connected to both Bluetooth devices and music instruments alike. It's IP54 dust protected and water resistant, comes in both Skyscraper Black and Olympic White, and sports an 18-hour battery life. For serenades at the park and impromptu shows for friends, it does the trick." data-dimension48="Need a portable amp that doesn't break your back every time you pick it up? Meet the Fender Audio ELIE 6. This 4-pound speaker delivers strong mids and treble when connected to both Bluetooth devices and music instruments alike. It's IP54 dust protected and water resistant, comes in both Skyscraper Black and Olympic White, and sports an 18-hour battery life. For serenades at the park and impromptu shows for friends, it does the trick." data-dimension25="$299">View Deal</a></p></div><h2 id="it-s-a-decent-little-bluetooth-speaker">It's a decent little Bluetooth speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4032px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="J2jU7sjCQ9oNSX5iFiQkt7" name="Fender-Elie-Speaker-1" alt="A Fender Audio ELIE 6 in a small room." src="https://cdn.mos.cms.futurecdn.net/J2jU7sjCQ9oNSX5iFiQkt7.jpg" mos="" align="middle" fullscreen="" width="4032" height="2268" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Although it doubles as an amp, the ELIE 6 is a Bluetooth speaker first and foremost — and it does a competent job in this role. It doesn’t bring the wall-shaking party the same way the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-4-review">JBL Xtreme 4</a> does, nor does it have the <a href="https://www.tomsguide.com/audio/sony-ult-field-5-review">Sony Ult Field 5’s</a> lightshow, but the sound profile is refined and relatively bassy.  </p><p>In terms of size, it's not all that big. It's only 7.7 x 4.8 x 4.1 inches, so it's easy to throw in a bag. </p><p>To put it through its paces, I used my usual speaker testing playlist that includes songs from Paramore, Eminem, Jimi Hendrix and John Williams. </p><p>By and large, the highs and mids are clear and precise at a moderate volume level and only begin to distort as you push it to 11... I mean full volume. (Sadly there's no <em>actual</em> 11...) </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4032px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="zdKABwvLHvhBCH9e9TpiG8" name="Fender-Elie-Speaker" alt="A Fender Audio ELIE 6 in a small room." src="https://cdn.mos.cms.futurecdn.net/zdKABwvLHvhBCH9e9TpiG8.jpg" mos="" align="middle" fullscreen="" width="4032" height="2268" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>It's bass levels that are very underserved in this speaker, though it's not for a lack of trying. There's a woofer at the bottom of the speaker that does its best to produce low-end frequencies, but the small form factor prevents it from reaching any form of meaty sub-bass.</p><p>If you want to double your output, you can sync up a second ELIE 6 speaker in either stereo, or round up a whole group of speakers if you want to turn your garage into a Guitar Center.</p><p>Personally, the ELIE 6 isn't going to replace my critical listening open-back headphones anytime in the near future, but for small gatherings, it's perfect.</p><h2 id="a-portable-amp-you-ll-want-to-bring-everywhere">A portable amp you'll want to bring everywhere</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:5022px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WrCMxkTvoVzt8a3ownkSC9" name="Fender-Elie-Speaker-2" alt="A Fender Audio ELIE 6 in a small room." src="https://cdn.mos.cms.futurecdn.net/WrCMxkTvoVzt8a3ownkSC9.jpg" mos="" align="middle" fullscreen="" width="5022" height="2825" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Whatever you feel about the speaker's sound quality, it's not the whole reason to buy an ELIE 6. You're choosing it over the competition because it doubles as a portable amplifier. </p><p>Now, I’ve never been a road musician, but I’ve carried my fair share of amps for friends and my older brother. Compared to schlepping a traditional 40-pound amplifier around, however, moving the 4-pound ELIE 6 around is a breeze.</p><p>Connecting my Ibanez bass was as simple as plugging in the jack, and volume is controlled by the knob on the right of the controls.</p><div><blockquote><p>There is a very specific kind of person out there that's going to love this speaker. </p></blockquote></div><p>I was able to play a few renditions of my favorite Red Hot Chili Pepper songs, and the sound quality was good. Again, there was no floor-shaking rumble to it, but I have a sneaking suspicion that the amp likely serves guitarists better than bassists. </p><p>Overall, the ELIE 6 is the perfect size and volume level take outside to a park and play for some friends. </p><h2 id="is-the-fender-elie-6-worth-300">Is the Fender ELIE 6 worth $300? </h2><p>There is a very specific kind of person out there that's going to love this speaker. </p><p>It's not the person who wants crystalline-clear sound quality. It's not the person who wants all-day battery life. (Fender says the ELIE 6 is good for about 18 hours of playback, which felt right given my two days of testing.) But it's very appealing for someone who just wants one speaker that doubles as a Bluetooth device and an amp. </p><p>If that's you, rock on. Fender Audio's got you covered.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/im-soundtracking-my-summer-with-the-usd54-jbl-go-5-its-one-of-the-best-budget-speakers-ive-ever-used"><strong>I’m soundtracking my summer with the $54 JBL Go 5 — it’s one of the best budget speakers I’ve ever used</strong></a></li><li><a href="https://www.tomsguide.com/audio/earbuds/i-test-earbuds-for-a-living-and-these-are-the-12-best-cheap-earbuds-you-can-buy-right-now"><strong>I test earbuds for a living and these are the 12 best cheap earbuds you can buy right now</strong></a></li><li><a href="https://www.tomsguide.com/audio/headphones/airpods-max-2-are-my-favorite-over-ear-headphones-but-i-hate-that-i-cant-create-my-own-eq"><strong>AirPods Max 2 are my favorite over-ear headphones — but I hate that I can't create my own EQ</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I've been using this tiny Bluetooth speaker for 3 months — its surprisingly big sound has transformed my home listening (and it's on sale right now) ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/ive-been-using-this-tiny-speaker-for-3-months-and-its-surprisingly-big-sound-has-transformed-my-home-listening-and-its-on-sale-right-now</link>
                                                                            <description>
                            <![CDATA[ The Edifier ES20 is a tiny speaker that can withstand the elements and provide big sound, and it's currently on sale for a limited time. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">MmzBPYWuUuUTmo4oeFMgdA</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/KEmfsyHMnP7fbFHFMzw7Jg-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 16 May 2026 09:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/KEmfsyHMnP7fbFHFMzw7Jg-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Edifier ES20 Bluetooth speaker in ivory photographed on a gray table in front of a blue background. ]]></media:description>                                                            <media:text><![CDATA[Edifier ES20 Bluetooth speaker in ivory photographed on a gray table in front of a blue background. ]]></media:text>
                                <media:title type="plain"><![CDATA[Edifier ES20 Bluetooth speaker in ivory photographed on a gray table in front of a blue background. ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/KEmfsyHMnP7fbFHFMzw7Jg-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Here at Tom's Guide, we're committed to helping you <a href="https://www.tomsguide.com/savings-squad">upgrade your life for less</a> by finding gadgets that can make everything a little easier without breaking the bank. And that includes making sure you have the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> on hand for summer parties and personal listening. </p><p>If you haven't already, now's the time to get your hands on an audio upgrade for the summer, and I'm here to tell you that it doesn't have to be from one of the most expensive brands like Sonos or Bose. You can find decent audio performance for well under $100; you just have to know where to look. </p><p>One of my top recommendations for this summer is the <a href="https://www.amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow">Edifier ES20, which is currently on sale at Amazon for $69</a>. It's small but mighty, and is a perfect option for outdoor gatherings. Here are my favorite things about the speaker. </p><div class="product"><a data-dimension112="6bdc090c-4fda-4aff-ae53-c5f0781685e5" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69" href="https://www.amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:444px;"><p class="vanilla-image-block" style="padding-top:112.61%;"><img id="NU43UEyEPMFupBtxZuNuJ6" name="edifier-es20-portable-bluetooth-speaker--9961544e-fd18-41de-b929-b92bed2e028c.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/NU43UEyEPMFupBtxZuNuJ6.jpg" mos="" align="middle" fullscreen="" width="444" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review" data-dimension112="6bdc090c-4fda-4aff-ae53-c5f0781685e5" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69">Edifier ES20</a> is a powerful, stylish speaker with remarkably loud output — it seriously shocked me. The speaker has a durability rating of IP67,  and has a stereo pairing option for bigger sound. I’d recommend it to the more budget-conscious among you who still want great sound performance.<a class="view-deal button" href="https://www.amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow" data-dimension112="6bdc090c-4fda-4aff-ae53-c5f0781685e5" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Xp4N4X"></div>                            </div>                            <script src="https://kwizly.com/embed/Xp4N4X.js" async></script><h2 id="premium-and-weatherproof-design">Premium and weatherproof design </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nKgLaXwrZFj2H8MgvASwNG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/nKgLaXwrZFj2H8MgvASwNG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Edifier ES20 is one good-looking speaker. It comes in ivory or black, and both versions of the speaker look premium with champagne accents and a metal grille on the front, which is reminiscent of the <a href="https://www.tomsguide.com/audio/marshall-willen-ii-review-rugged-rockin-fun">Marshall Willen II</a>. </p><p>It's a very small speaker, measuring just 3.7 x 3.6 x 2.0 inches, but don't let that put you off because its sound is larger than life. The size makes it easily portable, so it can go absolutely anywhere.</p><p>Beyond the good looks, there is functionality too. The speaker has an IP67 rating, meaning it's fully protected against dust and can even be submerged underwater. So there's no fear if it happens to fall into the pool by mistake!</p><h2 id="it-gets-very-loud">It gets very loud</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hKXzdWbfyxAswY3SdqeAJG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/hKXzdWbfyxAswY3SdqeAJG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As I was saying, don't let that small size deter you. This speaker can get incredibly loud — I was seriously shocked. When using the speaker indoors, I could hear it clearly from the other side of my house. And the sound carries well outside, too.</p><p>It rivals some bigger boombox-style speakers I've tested in the past, such as the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit Stormbox Lava</a>. At the lowest volumes, the Edifier starts to struggle with a little static in the bass, but that's to be expected. </p><h2 id="and-you-can-go-louder">And you can go louder</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="sVLerSfHyqgZUUfV6UnvdG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/sVLerSfHyqgZUUfV6UnvdG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Speaking of loud, the Edifier ES20 has stereo pairing capabilities. That means if you have more than one of the speakers (and at that price, why wouldn't you?), then you can pair them to create a surround sound setup. </p><p>This can create a more immersive sound for casual listening too, with a wider sound stage to support instrument separation and avoid static. </p><p>This is a speaker I'm going to be reaching for all summer long, but how about you? If you like the sound of this small but mighty speaker, you can read my full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review">Edifier ES20 review</a> to find out more. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review#section-edifier-es20-review-sound-quality">This budget speaker looks totally premium — and it almost nails it in the sound department too</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/expensive-doesnt-mean-good-heres-why-ill-be-sticking-with-my-usd40-speaker-over-this-usd200-one">'Expensive doesn’t mean good’: here’s why I’ll be sticking with my $40 speaker over this $200 one</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/you-dont-have-to-buy-the-newest-or-most-expensive-bluetooth-speaker-for-awesome-sound-here-are-my-top-picks-for-any-occasion-that-wont-break-the-bank">You don't have to buy the most expensive Bluetooth speaker for awesome sound — here are my top picks under $30, $50 and $100</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ You don't have to buy the most expensive Bluetooth speaker for awesome sound — here are my top picks under $30, $50 and $100 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/you-dont-have-to-buy-the-newest-or-most-expensive-bluetooth-speaker-for-awesome-sound-here-are-my-top-picks-for-any-occasion-that-wont-break-the-bank</link>
                                                                            <description>
                            <![CDATA[ Impressive and reliable sound quality is the main thing we want from our Bluetooth speakers, but you don't have to break the bank to get it. Here are my top recommendations for cheap Bluetooth speakers. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5aHpeeQPm3j24P6RsVDRUm</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/dd9s3SYzTf5GWU8ZwfWVjc-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 13 May 2026 06:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/dd9s3SYzTf5GWU8ZwfWVjc-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit StormBox Mini+]]></media:description>                                                            <media:text><![CDATA[Tribit StormBox Mini+]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit StormBox Mini+]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/dd9s3SYzTf5GWU8ZwfWVjc-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As part of the reviews team here at Tom's Guide, I spend a lot of my time testing the newest Bluetooth speakers. That means a lot of time with music booming in my ears while judging what products are actually worth your money. </p><p>One thing I've learned along the way is that spending more money doesn't always get you better sound quality performance, and sometimes you can get exactly what you need by picking some of the cheapest options. </p><p>I've put together a list of some of my favorite speakers that provide awesome sound and don't break the bank from budget brands. The <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> have been tested by the Tom's Guide team, so you can know exactly what to expect when you try them out. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Xp4N4X"></div>                            </div>                            <script src="https://kwizly.com/embed/Xp4N4X.js" async></script><h3 class="article-body__section" id="section-under-30"><span>Under $30</span></h3><div class="product"><a data-dimension112="b8dbce33-b3f5-4899-8dbf-7ce00aa32678" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="QwoNgHYEJaENwsdk2oFTEN" name="tribit-pocketgo-bluetooth-shower-speaker-6a5e355a-8fc0-4f0f-b56c-49912afec858.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/QwoNgHYEJaENwsdk2oFTEN.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review" data-dimension112="b8dbce33-b3f5-4899-8dbf-7ce00aa32678" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24">Tribit PocketGo</a> is the ultimate all-rounder speaker. I rely on it for pretty much every situation, and it never fails to bring the volume while maintaining well-balanced sound. The audio quality is great, making my favorite songs sound amazing, and some EQ adjustments in the companion app can make the sound even better. The PocketGo has a durability rating of IP68, so it can even withstand being submerged underwater and has military-grade drop resistance. The 20 hours of battery life are the cherry on top for this reliable and compact speaker. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="b8dbce33-b3f5-4899-8dbf-7ce00aa32678" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$24">View Deal</a></p></div><h3 class="article-body__section" id="section-under-50"><span>Under $50</span></h3><div class="product"><a data-dimension112="796080cb-91d6-436e-97a8-2e0e6ae55ce7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$33" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="PjiD4CP7xSse5XVWDtdbDN" name="tribit-stormbox-mini-portable-bluetooth--cdd1c005-f10b-45cf-927a-0755031f0a8b.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/PjiD4CP7xSse5XVWDtdbDN.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review" data-dimension112="796080cb-91d6-436e-97a8-2e0e6ae55ce7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$33">Tribit StormBox Mini+</a> is one of the best-performing speakers you can get in this price range. Retailing for just $39 (but it can often be found on sale at Amazon), it boasts a powerful bass response that will blow you away despite its small size, and detailed vocals to hear your favorite music in detail. The StormBox Mini+ also sports reactive LED lighting, which can create a party while listening, and it has an IPX7 waterproofing so it can be used poolside or in the shower. This speaker also supports stereo sound if you purchase two speakers.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5" target="_blank" rel="nofollow" data-dimension112="796080cb-91d6-436e-97a8-2e0e6ae55ce7" data-action="Deal Block" data-label="Tribit StormBox Mini+" data-dimension48="Tribit StormBox Mini+" data-dimension25="$33">View Deal</a></p></div><h3 class="article-body__section" id="section-under-100"><span>Under $100 </span></h3><div class="product"><a data-dimension112="5db087fc-43f2-49b0-8892-81ee0711a0d8" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69" href="https://amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:444px;"><p class="vanilla-image-block" style="padding-top:112.61%;"><img id="2F8oyE77dSBW5A2PmGNaGN" name="edifier-es20-portable-bluetooth-speaker--844f6681-92f0-489d-9590-03367ae9dd47.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/2F8oyE77dSBW5A2PmGNaGN.jpg" mos="" align="middle" fullscreen="" width="444" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review" data-dimension112="5db087fc-43f2-49b0-8892-81ee0711a0d8" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69">Edifier ES20</a> is a powerful, stylish speaker with remarkably loud output — it seriously shocked me.  The speaker has a durability rating of IP67, meaning it has total protection from dust and can even be submerged underwater and come out unscathed. It even comes with a stereo pairing option for creating better sound. It excels with electronic/pop music, but heavier rock music suffers from static, so that's worth keeping in mind. There's no custom EQ option either, so music tech fanatics may feel let down. Even so, the ES20 is under $90 (and can often be found on sale), so I’d recommend it to the more budget-conscious among you who still want great sound performance.<a class="view-deal button" href="https://amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow" data-dimension112="5db087fc-43f2-49b0-8892-81ee0711a0d8" data-action="Deal Block" data-label="Edifier ES20" data-dimension48="Edifier ES20" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="3554e5d3-87a6-4109-aa8e-55ee8de836f8" data-action="Deal Block" data-label="Ultimate Ears Wonderboom 4" data-dimension48="Ultimate Ears Wonderboom 4" data-dimension25="$75" href="https://www.amazon.com/Ultimate-Ears-WONDERBOOM-360-Degree-Waterproof/dp/B0BRXJVG1S" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="fAXDxNTSGFtGXhVjrn4hEN" name="ultimate-ears-wonderboom-4-portable-wate-0a5f918d-ac0a-47ac-ab31-81356141c022.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fAXDxNTSGFtGXhVjrn4hEN.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review" data-dimension112="3554e5d3-87a6-4109-aa8e-55ee8de836f8" data-action="Deal Block" data-label="Ultimate Ears Wonderboom 4" data-dimension48="Ultimate Ears Wonderboom 4" data-dimension25="$75">Ultimate Ears Wonderboom 4</a> is a small speaker with <em>huge</em> sound. Despite its light build, this speaker has sound that really packs a punch. But that loud volume comes with a downside because it vibrates with high volumes, but mid-volumes give great sound. It also looks good, with a slick style and large volume control buttons that are convenient for quick volume changes, and the funky color options mean there's an option for everyone. The Wonderboom 4 is ready for anything because it's waterproof, dustproof and drop-proof, making it the ideal companion for pool days, outdoor gatherings or just playing music in your room. <a class="view-deal button" href="https://www.amazon.com/Ultimate-Ears-WONDERBOOM-360-Degree-Waterproof/dp/B0BRXJVG1S" target="_blank" rel="nofollow" data-dimension112="3554e5d3-87a6-4109-aa8e-55ee8de836f8" data-action="Deal Block" data-label="Ultimate Ears Wonderboom 4" data-dimension48="Ultimate Ears Wonderboom 4" data-dimension25="$75">View Deal</a></p></div><div class="product"><a data-dimension112="b0ef89a0-1199-4876-8c1c-9fa805ee2bee" data-action="Deal Block" data-label="Soundcore Boom 2 Plus" data-dimension48="Soundcore Boom 2 Plus" data-dimension25="$99" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="7CMX7MYPkyoz6GXnED5aFN" name="soundcore-boom-2-by-anker-outdoor-speake-20a49e2c-a8a8-4642-940b-74764d46ae29.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/7CMX7MYPkyoz6GXnED5aFN.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/soundcore-boom-2-plus-review" data-dimension112="b0ef89a0-1199-4876-8c1c-9fa805ee2bee" data-action="Deal Block" data-label="Soundcore Boom 2 Plus" data-dimension48="Soundcore Boom 2 Plus" data-dimension25="$99">Soundcore Boom 2 Plus</a> is a boombox-style speaker that is sure to impress any friends you have over, if not for its flashy built-in lighting, then for the floor-shaking bass. I mean, seriously, if you purchase this speaker, I feel bad for your neighbours. It handles a variety of genres with ease, and vocals stand out. It has a handy carry strap and handle, and is lightweight compared to other large speakers, so it's a great option for outdoors... although it doesn't have any dustproofing, so make sure there's no sand around. <a class="view-deal button" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow" data-dimension112="b0ef89a0-1199-4876-8c1c-9fa805ee2bee" data-action="Deal Block" data-label="Soundcore Boom 2 Plus" data-dimension48="Soundcore Boom 2 Plus" data-dimension25="$99">View Deal</a></p></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested the JBL Xtreme 5 for a week and I'm obsessed — this upgrade needs to come to every Bluetooth speaker ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-tested-the-jbl-xtreme-5-for-a-week-and-im-obsessed-this-upgrade-needs-to-come-to-every-bluetooth-speaker</link>
                                                                            <description>
                            <![CDATA[ I tested the brand-new JBL Xtreme 5, and it boasts one major upgrade I hope comes to every Bluetooth speaker. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">BGnFcb4MZN3otp9YLzPwah</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/MhmJUtGJcUZLnrZejP3SpU-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 02 May 2026 10:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ erin.bashford@futurenet.com (Erin Bashford) ]]></author>                    <dc:creator><![CDATA[ Erin Bashford ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/rLvJvJVZx43hEzSsJy3BpL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Erin Bashford is a senior reviews writer at Tom’s Guide. She has a Master’s in Broadcast and Digital Journalism from the University of East Anglia and 7 years of experience reviewing music and events for various publications. She has edited publications such as Outline Magazine’s Guide to Norwich, and she has written for a number of music magazines and websites such as Clash Magazine, Outline Magazine and Dork Magazine. She has a strong interest in audio gear and the music world. &lt;/p&gt;&lt;p&gt;As an ex-barista, Erin is passionate about coffee tech. She also loves finding the best cooking hacks and kitchen appliances, including her beloved Instant Pot. &lt;/p&gt;&lt;p&gt;In her spare time, you can find her reading, practising yoga, hiking, writing fantasy novels, or stressing over NYT Games.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/MhmJUtGJcUZLnrZejP3SpU-1280-80.jpg">
                                                            <media:credit><![CDATA[Erin Bashford]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[the jbl xtreme 5 with water splashing on it outside in the park showing its waterproofing]]></media:description>                                                            <media:text><![CDATA[the jbl xtreme 5 with water splashing on it outside in the park showing its waterproofing]]></media:text>
                                <media:title type="plain"><![CDATA[the jbl xtreme 5 with water splashing on it outside in the park showing its waterproofing]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/MhmJUtGJcUZLnrZejP3SpU-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've tested tons of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers,</a> but none hold as special a place in my heart as the JBL Xtreme series. I loved the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-4-review">Xtreme 4</a> back when it was released in 2024, and I love the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review">Xtreme 5</a> in 2026. Though pricey, these are the two boombox-meets-portable party speakers I'd invest in for myself. </p><p>But the Xtreme 5 comes with <em>one</em> major upgrade I've never personally seen on a speaker before — not one I've tested myself, anyway. The Xtreme 5 has an IP68 rating, meaning it has the highest-possible durability rating. Yes, this speaker is not only 99.9% waterproof, dustproof, it's now drop-proof, too. </p><p>I hope this upgrade comes to every major speaker in the future, because I don't want to live without it now. </p><h2 id="xtreme-5-is-surviving-the-apocalypse">Xtreme 5 is surviving the apocalypse </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="Nw44CQNChUFixU37U852oZ" name="JBL_extreme_511.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/Nw44CQNChUFixU37U852oZ.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>An IP68 rating is pretty cutting-edge. It means the Xtreme 5 has the highest possible waterproof and dustproof rating. The "6" means the speaker is as protected as physically possible from dust ingress, while "8" means the speaker will survive sitting at the bottom of a pool. </p><p>Here's the caveat: while there is "technically" an IPX9 rating, this is an industrial-grade rating not really seen on consumer tech because it means the product can withstand high-pressure jets of near-boiling water. This just isn't a scenario most people will experience during backyard parties, so speaker brands don't really bother with IPX9. </p><p>IP68 is, generally, the best you can get. </p><div><blockquote><p>Surviving a five-and-a-half foot drop is more than I can say for my iPhone screen. RIP. </p></blockquote></div><p>But JBL went one step further — the Xtreme 5 is also "drop-proof". To test this out, I dropped it onto gravel from a height of 5-and-a-half feet, and it <em>bounced</em>. My music didn't stop playing. Honestly, I was a bit scared to drop it from a higher height — I was wary of dropping it out of my first-floor window to avoid hitting a passerby — but surviving a five-and-a-half foot drop is more than I can say for my iPhone screen. RIP. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="pPUJps4FCLUDQibmyso8Ja" name="JBL_extreme_501.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/pPUJps4FCLUDQibmyso8Ja.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This advanced level of durability is what makes it perfect for pool parties, beach parties, backyard parties, full moon parties, and anything else you could think of. </p><p>And, now that JBL has done it (JBL Xtreme 5, <a href="https://www.tomsguide.com/audio/speakers/jbl-charge-6">JBL Charge 6</a>, JBL Flip 7), <em>and</em> Tribit has done it (<a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0GF6PPS4S" target="_blank" rel="nofollow">Tribit StormBox Micro 3</a>), hopefully, we'll start seeing an IP68 rating more and more. </p><h2 id="but-it-s-not-just-about-durability">But it's not just about durability</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="aZgYJW4SUikecSyuNtX5Ka" name="JBL_extreme_508.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/aZgYJW4SUikecSyuNtX5Ka.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Of course, one thing is even more important than durability: sound quality. As a speaker, the JBL Xtreme 5 literally has one job — sound incredible.</p><p>And, boy, does it sound incredible. I adore this punchy, bassy, ferocious speaker. It's wide, expansive, and room/park-filling. When I use this speaker, I spend half my time worrying I'm going to get a noise complaint from my neighbors, but the other half of the time, I'm having way too much fun to care. </p><div><blockquote><p>When I use this speaker, I spend half my time worrying I'm going to get a noise complaint from my neighbors.</p></blockquote></div><p>In my 4.5-star review of the Xtreme 5, which you can read if you want more information, I wrote, "When the beat dropped, my entire desk started shaking. The bass squelched and oozed out of the speaker, a bouncing quagmire after sucking down a few amps."</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="wV4XWZtSdGirgwXHvkpU7a" name="JBL_extreme_513.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/wV4XWZtSdGirgwXHvkpU7a.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>While you won't get the clarity you'd expect for bookshelf speakers or the best smart speakers (like the <a href="https://www.tomsguide.com/audio/speakers/denon-home-400-review">Denon Home 400</a>, which I recently tested and love), but if you want a portable, meaty, and fearless speaker, I completely recommend the Xtreme 5. </p><p>That being said, if JBL can do it, why can't everyone else do it? Bose, Marshall, Sonos, I'm waiting!</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-WVq10e"></div>                            </div>                            <script src="https://kwizly.com/embed/WVq10e.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/earbuds/earfun-clip-2-review"><strong>I've been testing this new open-earbud upgrade from EarFun — and they're an instant win for gym goers</strong></a></li><li><a href="https://www.tomsguide.com/audio/earbuds/best-noise-canceling-earbuds"><strong>These are the best noise canceling earbuds that are actually worth your money right now</strong></a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-vs-jbl-xtreme-4"><strong>I tested the JBL Xtreme 5 vs JBL Xtreme 4 — and it's closer than I thought</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested the JBL Xtreme 5 vs JBL Xtreme 4 — and it's closer than I thought ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-vs-jbl-xtreme-4</link>
                                                                            <description>
                            <![CDATA[ Should you buy the new JBL Xtreme 5 or save your money and get the older JBL Xtreme 4? I've reviewed both, so I'll help you choose. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">vZSqGbmibADUX3QzWsP3FK</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/Z5AzwrgtzyqbK7ZQDqRP2a-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 26 Apr 2026 12:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ erin.bashford@futurenet.com (Erin Bashford) ]]></author>                    <dc:creator><![CDATA[ Erin Bashford ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/rLvJvJVZx43hEzSsJy3BpL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Erin Bashford is a senior reviews writer at Tom’s Guide. She has a Master’s in Broadcast and Digital Journalism from the University of East Anglia and 7 years of experience reviewing music and events for various publications. She has edited publications such as Outline Magazine’s Guide to Norwich, and she has written for a number of music magazines and websites such as Clash Magazine, Outline Magazine and Dork Magazine. She has a strong interest in audio gear and the music world. &lt;/p&gt;&lt;p&gt;As an ex-barista, Erin is passionate about coffee tech. She also loves finding the best cooking hacks and kitchen appliances, including her beloved Instant Pot. &lt;/p&gt;&lt;p&gt;In her spare time, you can find her reading, practising yoga, hiking, writing fantasy novels, or stressing over NYT Games.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/Z5AzwrgtzyqbK7ZQDqRP2a-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:description>                                                            <media:text><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:text>
                                <media:title type="plain"><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/Z5AzwrgtzyqbK7ZQDqRP2a-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div class="featured_product_block featured_block_versus" data-id="565d8899-10b2-4917-9f05-119aa0d4644a">            <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3" data-model-name="Xtreme 4" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/L2TjtWjKvMz35uXeyxCSKR.jpg" alt="JBL Xtreme 4"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>JBL</div>                    <div class="featured__title">Xtreme 4</div>                                    </div>                <div class="subtitle__description">                                                            <p><p>The JBL Xtreme 4 perfectly bridges the gap between portable outdoor speaker and a ferocious, bassy boombox. </p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_versus" data-id="1f459c87-0e2c-42de-ab22-022a0b7fc043">            <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9" data-model-name="Xtreme 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/tQ9AuHnACGmgriw2w7EMg3.png" alt="the jbl xtreme 5 on a white square background"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>JBL</div>                    <div class="featured__title">Xtreme 5</div>                                    </div>                <div class="subtitle__description">                                                            <p><p>The JBL Xtreme 5 is the grown-up version of the Xtreme 4: bigger, bolder, brawnier. It's the loudest speaker I've ever tested. </p></p>                </div>                            </div>        </div><p>Upon its release in 2024, the<a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-4-review"> JBL Xtreme 4</a> instantly positioned itself as one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> ever made. Well, now the <a href="https://tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review">JBL Xtreme 5</a> is here, so it got me thinking: Can JBL top near-perfection? </p><p>I'm not going to answer that right away — magicians don't reveal their secrets at the start of the show, do they? — but I am going to give you some hints. The Xtreme 5 comes with a smattering of changes, both big (literally) and small. Surprisingly, the Xtreme 5 has grown a few inches in both length and girth, gained a few pounds, and acquired a semi-drunken light show, kind of like me at Christmas. </p><p>But those extra pounds aren't for nothing. The Xtreme 5 is, pardon the pun, xtremely loud. And bassy. And ferocious. When I was testing the speaker in my apartment and in the local park, I worried I'd get a few noise complaints. I didn't, but if that's the kind of speaker you're after, you'll want to keep reading to figure out if you should buy the JBL Xtreme 5 or JBL Xtreme 4. </p><h3 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-specs-compared"><span>JBL Xtreme 5 vs JBL Xtreme 4: Specs compared</span></h3><div ><table><thead><tr><th class="firstcol " ><p>Feature</p></th><th  ><p>JBL Xtreme 4</p></th><th  ><p>JBL Xtreme 5</p></th></tr></thead><tbody><tr><td class="firstcol " ><p>Price</p></td><td  ><p>$379 / £329 (Launch)</p></td><td  ><p>$399 / £299</p></td></tr><tr><td class="firstcol " ><p>Colors</p></td><td  ><p>Black, Navy, Camo</p></td><td  ><p>Black, Navy, Camo</p></td></tr><tr><td class="firstcol " ><p>Size</p></td><td  ><p>5.8 x 11.7 x 5.5 inches</p></td><td  ><p>6.1 x 13.6 x 6.5 inches</p></td></tr><tr><td class="firstcol " ><p>Weight</p></td><td  ><p>4.63 pounds</p></td><td  ><p>6.4 pounds</p></td></tr><tr><td class="firstcol " ><p>Battery Life</p></td><td  ><p>24 hours</p></td><td  ><p>28 hours</p></td></tr><tr><td class="firstcol " ><p>Connectivity</p></td><td  ><p>Bluetooth 5.3</p></td><td  ><p>Bluetooth 6.0</p></td></tr><tr><td class="firstcol " ><p>Durability</p></td><td  ><p>IP67</p></td><td  ><p>IP68</p></td></tr><tr><td class="firstcol " ><p>Multi-speaker</p></td><td  ><p>Auracast</p></td><td  ><p>Auracast</p></td></tr><tr><td class="firstcol " ><p>Freq. Response</p></td><td  ><p>44Hz - 20kHz</p></td><td  ><p>40Hz - 20kHz</p></td></tr><tr><td class="firstcol " ><p>Range</p></td><td  ><p>~100 feet</p></td><td  ><p>Not specified</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-price"><span>JBL Xtreme 5 vs JBL Xtreme 4: Price</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="Pxa5kX2RrieVaEeUz3iQ4a" name="JBL_extreme_517.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/Pxa5kX2RrieVaEeUz3iQ4a.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The JBL Xtreme 4 launched in 2024 with an MSRP of $379. You can buy it on <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-PartyBoost-Multi-speaker/dp/B0CTP191Z3" target="_blank" rel="nofollow">Amazon right now, still for that launch price of $379</a>. Comparatively, the JBL Xtreme 5 launched at <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9" target="_blank" rel="nofollow">$399, available on Amazon</a>. </p><p>I was disappointed to see this 5% price increase over the previous model. The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">Go 5</a> launched on the same day as the Xtreme 5 with a $5 increase, which works out to 10%. I suppose we should be glad the Xtreme 5 didn't get this 10% increase, but $20 is noticeable. </p><p>As the Xtreme 4 is now the older model, we should start seeing great discounts. I'm not sure when said discounts will kick in, but keep your eyes peeled as we approach major sales events like Black Friday. </p><p><strong>Winner: </strong>JBL Xtreme 4. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-design"><span>JBL Xtreme 5 vs JBL Xtreme 4: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3zYBWHAnjaqGkGRPifdDbH" name="JBL_Xtreme4_04.JPG" alt="close up photograph of a big outdoor bluetooth speaker by JBL Xtreme 4" src="https://cdn.mos.cms.futurecdn.net/3zYBWHAnjaqGkGRPifdDbH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As you can see from the 'Specs compared' section above, the Xtreme 5 is considerably larger than the Xtreme 4. I'm not entirely sure why JBL did this, as the brand already has the Boombox 3, which is 19 inches long and weighs 14.7 pounds. As the Xtreme 5 is 13.6 inches long and 6.4 pounds, it's still a lot smaller than the Boombox, but it's also a lot bigger than the previous model. </p><p>The whole "point" of the Xtreme line is boombox performance without boombox size. Yes, it's not quite boombox size, but every little helps, right? When I unboxed the Xtreme 5, the first thing I thought was, "Oh darn, that's bigger." If you already thought the Xtreme 4 was too big, then I don't think the 5 will be for you either. For seriously portable speakers, you might want to check out the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet">Flip 7</a> or <a href="https://www.tomsguide.com/audio/speakers/jbl-charge-6">Charge 6</a>, just 1.8 and 2.7 pounds, respectively. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="GYHVas7y6CD8EpWrLLVDFa" name="JBL_extreme_510.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/GYHVas7y6CD8EpWrLLVDFa.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This extra weight has its advantages: The Xtreme 5 is louder, bassier, and more durable than its predecessor. You're looking at an IP68 rating, the highest durability rating a speaker can get. Essentially, this means it can be buried in sand, thrown in the ocean, dropped from a great height, and will still keep the party going. You won't find a more rugged speaker. </p><p>Speaking of ruggedness, both the Xtreme 4 and 5 have the durable carry strap for traversing across beaches, parks, deserts, mountains, and wherever you might want to take this speaker. </p><p>Controls are just as straightforward on either speaker: you've got some nice tactile buttons on the speaker body for play, pause, volume, and AuraCast.</p><p>Last but not least, there are two built-in LED strips. Yes, the Xtreme 5 keeps the party going in sound and also vibes. You can adjust the light color and style in the JBL Portable app. This light show isn't as extravagant as, say, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-blast-2-review">Tribit StormBox Blast 2</a>, but it's still fun.  </p><p>Even though the 4 is considerably lighter and more portable than the 5, I'm going to give the 5 the win. It's literally the most durable speaker you can buy, and it has lights.</p><p><strong>Winner: </strong>JBL Xtreme 5. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-features"><span>JBL Xtreme 5 vs JBL Xtreme 4: Features</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="uC2RabfrGDcpmWaC3fV76J" name="JBL_Xtreme4_03.JPG" alt="close up photograph of a big outdoor bluetooth speaker by JBL Xtreme 4" src="https://cdn.mos.cms.futurecdn.net/uC2RabfrGDcpmWaC3fV76J.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>As the Xtreme 4 and 5 are both party speakers, you'll be pleased to know they both come locked and loaded with AuraCast. If you ever find yourself at a party with multiple AuraCast speakers, you'll be able to sync them up using JBL's 'PartyTogether'. I found this very straightforward to set up in the JBL Portable app: the speakers just knew what they were doing and sorted themselves out. </p><p>The Xtreme 5 also comes with Bluetooth 6.0, which provides a decent range for outdoor usage. I was able to get out of my apartment and a little down the street before the speaker disconnected. </p><p>The Xtreme 5 has 'PartyBoost', which is effectively a battery longevity mode. The Xtreme 4 doesn't have this. With PartyBoost, the sound quality decreases slightly, but you can squeeze an extra four hours of playtime. You win some, you lose some, right? </p><p>As the 5 has PartyBoost, I'm giving this win to the newer model. </p><p><strong>Winner: </strong>JBL Xtreme 5. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-sound-quality"><span>JBL Xtreme 5 vs JBL Xtreme 4: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="Nw44CQNChUFixU37U852oZ" name="JBL_extreme_511.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/Nw44CQNChUFixU37U852oZ.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Both the Xtreme 5 and Xtreme 4 are characterized by loud, propulsive bass. If you want to soundtrack your house parties, pool parties, beach parties, or anything in between, I think you'd get on just fine with either speaker. However, the Xtreme 5 <em>just</em> ekes out the win, and let me tell you why. </p><div><blockquote><p>Because of its size, the Xtreme 5 has a more expansive, wider sound that reaches every corner of your house. </p></blockquote></div><p>Because of its size, the Xtreme 5 has a more expansive, wider sound that reaches every corner of your house. When I played 'REAL MOVE TOUCH' by Confidence Man, the bass pummeled through the Xtreme 5 like an uncontrollable conflagration intent on setting the dancefloor alight. </p><p>This isn't to say the Xtreme 4 performed badly — not in the slightest — but, as the 5 has those extra two inches over the 4, you've naturally got more width. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="w3XgT5CoPwKzRqvXzLAWuH" name="JBL_Xtreme4_10.JPG" alt="close up photograph of a big outdoor bluetooth speaker by JBL Xtreme 4" src="https://cdn.mos.cms.futurecdn.net/w3XgT5CoPwKzRqvXzLAWuH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Similarly, when I played 'All I Am' by Ninajirachi, the Xtreme 5 made the song feel bigger and bolder. The bass pounded through my desk without overpowering the female vocals. </p><p>In contrast, the Xtreme 4 had a little less bass and more roughness in the treble. Please don't think the Xtreme 4 sounds bad, because it sounds frankly divine, but the Xtreme 5 is just <em>so</em> darn near perfection. </p><p>I also played 'Artificial Angels' by Grimes, which is another party-ready electronic track. The glitchy, crawling bassline and frenetic synths stole the show on the Xtreme 5, compounded by the mesmerizing LED light show.</p><p>I really can't fault the Xtreme 5 — it's the best party speaker I've ever tested.</p><p><strong>Winner</strong>: JBL Xtreme 5.</p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-battery"><span>JBL Xtreme 5 vs JBL Xtreme 4: Battery</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="pPUJps4FCLUDQibmyso8Ja" name="JBL_extreme_501.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/pPUJps4FCLUDQibmyso8Ja.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This is an objective win: the Xtreme 5 is going to scoop this round. As the Xtreme 4 has 24 hours of battery life and the Xtreme 5 boasts 28 (with PartyBoost), I can't really do anything but name the 5 the champion here. </p><p><strong>Winner: </strong>JBL Xtreme 5. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-verdict"><span>JBL Xtreme 5 vs JBL Xtreme 4: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vMm2JLeYCaGcm3DepvickJ" name="JBL_Xtreme4_07.JPG" alt="close up photograph of a big outdoor bluetooth speaker by JBL Xtreme 4" src="https://cdn.mos.cms.futurecdn.net/vMm2JLeYCaGcm3DepvickJ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>I <em>love</em> the JBL Xtreme 5. It's one of my favorite speakers of all time, and it's definitely the "best" party/outdoor Bluetooth speaker you can get right now. </p><p>However, if you've already got an Xtreme 4 and you're considering upgrading, I think you should stick with your 4. Sure, the improvements are nice — lights, better sound, and more durability — but are they worth $400 when you already have a $380 speaker? Although the Xtreme 5 won every round, as you can see from the ratings scorecard, the results were closer than I'd predicted.</p><p>But if you don't have a party speaker and you're considering it, then you should 100% get the Xtreme 5. It's the best new speaker on the market. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-vs-jbl-xtreme-4-ratings-scorecard"><span>JBL Xtreme 5 vs JBL Xtreme 4: Ratings scorecard</span></h2><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p>JBL Xtreme 5</p></th><th  ><p>JBL Xtreme 4</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price and value (5)</strong></p></td><td  ><p>2</p></td><td  ><p>3</p></td></tr><tr><td class="firstcol " ><p><strong>Design (15)</strong></p></td><td  ><p>13</p></td><td  ><p>12</p></td></tr><tr><td class="firstcol " ><p><strong>Portability (5)</strong></p></td><td  ><p>2</p></td><td  ><p>3</p></td></tr><tr><td class="firstcol " ><p><strong>Controls (10)</strong></p></td><td  ><p>10</p></td><td  ><p>10</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity (20)</strong></p></td><td  ><p>20</p></td><td  ><p>19</p></td></tr><tr><td class="firstcol " ><p><strong>Features (10)</strong></p></td><td  ><p>9</p></td><td  ><p>8</p></td></tr><tr><td class="firstcol " ><p><strong>Sound quality (25)</strong></p></td><td  ><p>24</p></td><td  ><p>22</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (10)</strong></p></td><td  ><p>8</p></td><td  ><p>7</p></td></tr><tr><td class="firstcol " ><p><strong>Total Score (100)</strong></p></td><td  ><p>88</p></td><td  ><p>84</p></td></tr></tbody></table></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-WVq10e"></div>                            </div>                            <script src="https://kwizly.com/embed/WVq10e.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/im-soundtracking-my-summer-with-the-usd54-jbl-go-5-its-one-of-the-best-budget-speakers-ive-ever-used"><strong>I’m soundtracking my summer with the $54 JBL Go 5 — it’s one of the best budget speakers I’ve ever used</strong></a></li><li><a href="https://www.tomsguide.com/audio/earbuds/i-test-earbuds-for-a-living-and-these-are-the-12-best-cheap-earbuds-you-can-buy-right-now"><strong>I test earbuds for a living and these are the 12 best cheap earbuds you can buy right now</strong></a></li><li><a href="https://www.tomsguide.com/audio/headphones/airpods-max-2-are-my-favorite-over-ear-headphones-but-i-hate-that-i-cant-create-my-own-eq"><strong>AirPods Max 2 are my favorite over-ear headphones — but I hate that I can't create my own EQ</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested the JBL Go 5 vs JBL Go 4 budget Bluetooth speakers — and there’s a clear winner under $60 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-versus-jbl-go-4-face-off</link>
                                                                            <description>
                            <![CDATA[ The JBL Go 5 is here after a two-year wait, but is it any better than the JBL Go 4? I put the two budget Bluetooth speakers through their paces to find out. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">kth94ZaQEviQoAJdLwtSb9</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/E6ggBeiVE7NkyaKTsvNPr8-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 25 Apr 2026 13:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/E6ggBeiVE7NkyaKTsvNPr8-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Go 5 vs JBL Go 4]]></media:description>                                                            <media:text><![CDATA[JBL Go 5 vs JBL Go 4]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Go 5 vs JBL Go 4]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/E6ggBeiVE7NkyaKTsvNPr8-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div class="featured_product_block featured_block_versus" data-id="f1269684-c56b-415c-b9b4-d96c4af4882e">            <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHYJ7BS9/" data-model-name="Go 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/YHNWrEwxj5uzgYGXCTeiJ6.jpg" alt="JBL Go 5"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>JBL</div>                    <div class="featured__title">Go 5</div>                                    </div>                <div class="subtitle__description">                                <div class="stars__reviews"><span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="chunk rating"><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star half"></span><meta itemprop="bestRating" content="100.0" /><meta itemprop="worstRating" content="0.0" /><meta itemprop="ratingValue" content="90" /></span></div>                                        <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_versus" data-id="9c94ec87-5e72-4211-8910-738de48fcd9e">            <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNYC4BS/" data-model-name="Go 4" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/K7TuJbAknvrrwY5JV25oF8.jpg" alt="JBL Go 4"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>JBL</div>                    <div class="featured__title">Go 4</div>                                    </div>                <div class="subtitle__description">                                <div class="stars__reviews"><span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="chunk rating"><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><meta itemprop="bestRating" content="100.0" /><meta itemprop="worstRating" content="0.0" /><meta itemprop="ratingValue" content="80" /></span></div>                                        <p></p>                </div>                            </div>        </div><p>JBL knows how to make a good speaker. From chunky speakers, like the JBL Xtreme 5, to small ones that can be clipped onto a bike handle, like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-clip-5-review">JBL Clip 5</a>, there's no dearth of options in JBL's lineup. </p><p>In April 2026, JBL revealed the successor to its two-year-old <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-4-review">JBL Go 4</a> pocket speaker, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5</a>, and I've tested it for a week to come to the conclusion that it's the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best budget Bluetooth speaker </a>you can buy today.</p><p>But how does it compare to its predecessor? After all, the Go 4 is a formidable speaker that you can still buy today — often for less than $40 when it's on sale. I put the Go 5 and the Go 4 through their paces in this face-off to find out which is best value for money. I don't think the winner will surprise you that much.</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-specs"><span>JBL Go 5 vs JBL Go 4: Specs</span></h2><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p>JBL Go 5</p></th><th  ><p>JBL Go 4</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow">$54</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-AirTouch-Waterproof/dp/B0GPPRPRM5/" target="_blank" rel="nofollow">£39</a></p></td><td  ><p><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX/" target="_blank" rel="nofollow">$49</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-PlaytimeBoost-Waterproof/dp/B0CX5B4N1N/" target="_blank" rel="nofollow">£39</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, Blue, Pink, Purple, Red, Squad (camo), White</p></td><td  ><p>Black, White, Red, Blue, Pink, Purple, Camouflage</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>3.98 x 3.05 x 1.7 inches</p></td><td  ><p>3.7 x 3 x 1.7 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>8.16oz</p></td><td  ><p>6.7oz</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (rated)</strong></p></td><td  ><p>10 hours</p></td><td  ><p>7 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 6.0 with SBC, AAC and LC3</p></td><td  ><p>Bluetooth 5.3 with SBC and AAC</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP68</p></td><td  ><p>IP67</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-price-availability"><span>JBL Go 5 vs JBL Go 4: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="8xQWveEDZmFt23B5xnXZp4" name="JBL_Go_5_Blue01.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/8xQWveEDZmFt23B5xnXZp4.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The JBL Go 4, at the time of writing, is two years old as it first came out in early 2024. At launch, it had a retail price of <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX/" target="_blank" rel="nofollow">$49</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-PlaytimeBoost-Waterproof/dp/B0CX5B4N1N/" target="_blank" rel="nofollow">£39</a>, but as the speaker is a little old now, you can find down to $39 / £29 during sales events, like Black Friday. In April 2026, JBL revealed the JBL Go 5 with a launch price of <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow">$54</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-AirTouch-Waterproof/dp/B0GPPRPRM5/" target="_blank" rel="nofollow">£39</a> — a $5 price hike over its predecessor, which is practically unnoticeable.</p><p>In terms of sheer value for money, the Go 5 is the winner. It's newer and it improves on the fourth-gen model's shortcomings while introducing a couple new upgrades, as you'll soon see throughout this face-off.</p><p><strong>Winner: </strong>JBL Go 5</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-design"><span>JBL Go 5 vs JBL Go 4: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="n6bdW5KEedFhqGSbQhwfSD" name="JBL_Go4_01.JPG" alt="A photo of the JBL Go 4 in blue on a concrete surface against a blue wall." src="https://cdn.mos.cms.futurecdn.net/n6bdW5KEedFhqGSbQhwfSD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>If you weren't already familiar with the design differences between the JBL Go 5 and the JBL Go 4, and you were to put both speakers side-by-side, you probably wouldn't be able to tell which is which. The Go 5 bears striking resemblance to its predecessor as it continues to sport a boxy, rectangular design with mesh covers over the front and rear faces.</p><p>One of the key visual differences is that the Go 5 now features two strips of LED lighting which run along the base and the top plate, with four lighting effects. Rubber strips are located on both speakers. The Go 5 is a little heavier at 8.16oz, versus the Go 4 which weighs 6.7oz, but the difference is hardly noticeable. You can still carry both with ease, even in your jacket's pocket.</p><p>Controls are fairly similar too, so you can change the volume, enable Auracast, and swap between Bluetooth sources easily. Build quality of both speakers is sublime. In my opinion, the Go 5 is the winner as it's still pocketable and the LED lighting strips are a nice, classy touch.</p><p><strong>Winner: </strong>JBL Go 5</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-features-connectivity"><span>JBL Go 5 vs JBL Go 4: Features & connectivity</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="QCXByrQqe4S49LXVUWEoh5" name="JBL_Go_5_Blue10.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/QCXByrQqe4S49LXVUWEoh5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The JBL Go 4 utilizes Bluetooth 5.3 with support for SBC and AAC codecs, while the JBL Go 5 utilizes Bluetooth 6.0 with added support for LC3 for improved sound quality at lower bitrates. Both speakers are Auracast-enabled which means you can link multiple speakers together for bigger sound — or if you want to play the same song in different parts of a room.</p><p>In my testing, I found Auracast pairing to be a little finnicky on the Go 4, as it took a few tries to do so and I ended up using the companion app to make the process easier. On the Go 5, though, I found the process to be more straightforward as it took me hardly any time to pair multiple speakers together. The Go 5 has another ace up its sleeve too, in the form of AirTouch stereo pairing. If you have another Go 5, you can touch two Go 5s together to instantly create left and right stereo channels.</p><p>Both speakers are durable too. The Go 4 is IP67-rated while the Go 5 is IP68-rated, making the latter the better choice if you want to submerge it in 1.5m of water for 30 minutes. It's also drop-proof, and having dropped it from a height of approximately 2m onto a wooden floor, I can confirm that the Go 5 remained unscathed.</p><p><strong>Winner: </strong>JBL Go 5</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-sound-quality"><span>JBL Go 5 vs JBL Go 4: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rhoFbCRJyzK3pHmuqpWqUE" name="JBL_Go4_08.JPG" alt="A photo of the JBL Go 4 in hand." src="https://cdn.mos.cms.futurecdn.net/rhoFbCRJyzK3pHmuqpWqUE.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The biggest difference between the JBL Go 5 and the JBL Go 4 is the sound quality. Both speakers are highly competent, and they can get very loud, but the Go 5 is simply better because it delivers better sub-bass and general bass response. This was instantly clear in my testing.</p><p>To start, I listened to ‘<a href="https://open.qobuz.com/track/361933224" target="_blank" rel="nofollow">Elma</a>’ by Yin Yin, an atmospheric psychedelic rock and funk track. The Go 5 boasted impressive separation between the shimmering guitar and synth waves. There was plenty of low-end impact to each string plucked on the bass guitar too. Listening to the track on the Go 4 right after revealed a lack of warmth to the groovy bass, and it sounded hollow rather than full-bodied. I also noticed that I couldn't really hear the kickdrum through the Go 4, which made the track feel soulless, but this wasn't the case through the Go 5. The sub-bass sounded thick, warm and very enjoyable, and it gave a good backbone to the track.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="PteE7JXPDMnDiaH7dXGnJ5" name="JBL_Go_5_Blue05.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/PteE7JXPDMnDiaH7dXGnJ5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Lana Del Rey's ‘<a href="https://open.qobuz.com/album/gcsfc9y5o0or4" target="_blank" rel="nofollow">First Light</a>’ sounded fairly similar through both the speakers. "T" and "s" sounds remained crisp without becoming hissy, and the vocals shone through the track and didn't get drowned out by the orchestration. The treble sounded crisp, clean and vibrant without cutting through the rest of the track, lending the song a lovely energy.</p><p>An area where the Go 5 upstages the Go 4 is dynamic management, as in ‘<a href="https://open.qobuz.com/track/404364927" target="_blank" rel="nofollow">Who Will You Follow</a>' by Evanescence, I noticed the distorted, low-tuned guitars sounded a little muddy through the Go 4. This wasn't an issue on the Go 5, as the newer speaker handled the song with aplomb. There was a great balance between Amy Lee's high-pitched vocals and the gothic metal guitar riffs.</p><p>Based on sound quality alone, the Go 5 is a no-brainer. For such a tiny speaker, it can get very loud without music sounding distorted or too tinny at high volumes, and it quashes the Go 4 in every aspect.</p><p><strong>Winner: </strong>JBL Go 5</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-battery-life"><span>JBL Go 5 vs JBL Go 4: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="eyYVkdjMHBrEWZzUHhhWF5" name="JBL_Go_5_Blue07.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/eyYVkdjMHBrEWZzUHhhWF5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Both the JBL Go 4 and the JBL Go 5 are tiny speakers, so you shouldn't expect extensive battery lives from either. JBL has added a bigger battery pack to the Go 5, so you get 8 hours of playback time or 10 hours with Playtime Boost enabled via the app — a three-hour improvement over the Go 4. </p><p>In my testing, I was prompted to charge the Go 5 after 9 hours of listening to music at 50% volume, and to charge the Go 4 after 7 hours of doing the same.</p><p>The Go 5's playback time will also depend on whether the LED lighting is turned on or off, but both speakers should last you comfortably if you're hosting a barbecue or a poolside party with friends. Playtime Boost is a handy feature too, but note that it sacrifices some of the bass to last longer.</p><p><strong>Winner: </strong>JBL Go 5</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-verdict"><span>JBL Go 5 vs JBL Go 4: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="p8VCHkGpVagTBewo5bH4v5" name="JBL_Go_5_Blue12.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/p8VCHkGpVagTBewo5bH4v5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As you've seen throughout this face-off, and based on the ratings scorecard below, there's a clear winner, and it isn't even close. The JBL Go 5 wins in every category, from value for money and design to sound quality and battery life. While the Go 4 is good and can be a great speaker when picked up during sales events, the Go 5 is simply better.</p><p>If it's outstanding sound quality you're after, the Go 5 should be your port of call. It doesn't compromise on sound, boasting excellent sub-bass, meaty bass and vibrant treble. The Go 4 struggles when it comes to reproducing warm sub-bass, which can make songs feel hollow. </p><p>At the end of the day, both the Go 4 and the Go 5 are superb budget Bluetooth speakers, but the Go 5 is crowned the winner in this face-off because JBL has improved it in basically every way possible. Personally, it's my new favorite budget speaker that I'll be using for a long, long time.</p><h2 class="article-body__section" id="section-jbl-go-5-vs-jbl-go-4-ratings-scorecard"><span>JBL Go 5 vs JBL Go 4: Ratings scorecard</span></h2><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p>JBL Go 5</p></th><th  ><p>JBL Go 4</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price and value (5)</strong></p></td><td  ><p>5</p></td><td  ><p>4</p></td></tr><tr><td class="firstcol " ><p><strong>Design (15)</strong></p></td><td  ><p>15</p></td><td  ><p>13</p></td></tr><tr><td class="firstcol " ><p><strong>Portability (5)</strong></p></td><td  ><p>5</p></td><td  ><p>5</p></td></tr><tr><td class="firstcol " ><p><strong>Controls (10)</strong></p></td><td  ><p>10</p></td><td  ><p>10</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity (20)</strong></p></td><td  ><p>20</p></td><td  ><p>17</p></td></tr><tr><td class="firstcol " ><p><strong>Features (10)</strong></p></td><td  ><p>10</p></td><td  ><p>7</p></td></tr><tr><td class="firstcol " ><p><strong>Sound quality (25)</strong></p></td><td  ><p>24</p></td><td  ><p>20</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (10)</strong></p></td><td  ><p>10</p></td><td  ><p>7</p></td></tr><tr><td class="firstcol " ><p><strong>Total Score (100)</strong></p></td><td  ><p>99</p></td><td  ><p>83</p></td></tr></tbody></table></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-XkGx6X"></div>                            </div>                            <script src="https://kwizly.com/embed/XkGx6X.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">The JBL Go 5 is one of the best budget speakers I’ve tested, and it offers stellar sound for just $54</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-4-review">JBL Go 4 review</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/the-only-bluetooth-speaker-you-need-for-pool-parties-costs-less-than-usd40-no-im-not-joking">The only Bluetooth speaker you need for pool parties costs less than $40 — no, I’m not joking</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Bose, JBL and Anker Bluetooth speakers are up to $130 off in time for spring — 11 deals for the ultimate picnic vibe ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/bose-jbl-and-anker-bluetooth-speakers-are-up-to-usd130-off-in-time-for-spring-11-deals-for-the-ultimate-picnic-vibe</link>
                                                                            <description>
                            <![CDATA[ Some of the best speakers we've tested are hitting their lowest prices ever! Check out the deals I recommend from the biggest and best audio brands. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">UcgXUSTZHhEV3CNxDsjuzW</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/vgvEaWTQpq4dwYTpwTpc76-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 25 Apr 2026 10:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ millie.daviswilliams@futurenet.com (Millie Davis-Williams) ]]></author>                    <dc:creator><![CDATA[ Millie Davis-Williams ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/WU6pa7hKuxs5ScCoqcXYWA.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Millie is a Deals Editor at Tom&#039;s Guide specializing in tech deals content. Based in London, Millie has spent a lifetime stubbornly refusing to pay full price on any possible purchase. She has years of searching for the best discounts on the latest and greatest phones, TVs and gadgets under her belt, and knows how to sort the best deals from the rest. Helping readers save on the products they want is her mission, whether it’s an Apple Watch or a new tablet.&lt;/p&gt;&lt;p&gt;Since working at Tom’s Guide, Millie has covered retail events like Prime Day, Black Friday and Cyber Monday extensively, meaning she knows the products readers are looking for and the best times of year to hit “purchase.”&lt;/p&gt;&lt;p&gt;When she’s not looking for discounts, Millie covers news and writes how-to articles about everything from phones, streaming devices, and headphones to apps and video games.&lt;/p&gt;&lt;p&gt;In her spare time, Millie enjoys reading, gaming on her Nintendo Switch and creating digital art. She’s also a fan of watching Disney movies and collecting plush (the latter having totally taken over her bedroom.)&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/vgvEaWTQpq4dwYTpwTpc76-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Go 4 Bluetooth speaker on a table]]></media:description>                                                            <media:text><![CDATA[JBL Go 4 Bluetooth speaker on a table]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Go 4 Bluetooth speaker on a table]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/vgvEaWTQpq4dwYTpwTpc76-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Want to get the party started this spring? You don't need to spend a lot to do so, because many of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> are dropping in price. Whether it's Bose, JBL or Marshall, I'm truly impressed by the variety and quality of deals available right now.</p><p>For starters, the <a href="https://www.amazon.com/Marshall-Kilburn-Portable-Bluetooth-Speaker/dp/B0F967JT5Y" target="_blank" rel="nofollow">Marshall Kilburn III is on sale for $349 at Amazon</a>. It has an incredibly stylish retro design and extremely impactful sound. It's a good buy with $20 off, although it did sell for $299 over the holidays.</p><p>Or, if you want super-powerful, super-portable sound on a budget? Pick up the <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow">Tribit PocketGo for $19</a>. It offers unbelievably good audio for the price, as well as 20 hour battery life and IP68 water and dust resistance.</p><p>Keep scrolling to see all my favorite deals! I also recommend checking out our <a href="https://www.tomsguide.com/coupons/amazon.com">Amazon promo codes</a> and the <a href="https://www.tomsguide.com/home/ive-just-found-12-ikea-storage-ideas-that-are-perfect-for-my-tiny-entryway-all-under-usd20">best IKEA entryway finds</a>.</p><h2 class="article-body__section" id="section-quick-links"><span>Quick Links</span></h2><ul><li><a href="https://www.amazon.com/b?_encoding=UTF8&node=7073956011" target="_blank" rel="nofollow"><strong>shop Bluetooth speaker deals at Amazon</strong></a></li><li><strong>Tribit PocketGo: </strong><a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><strong>was $29 now $19</strong></a></li><li><strong>JBL Go 4: </strong><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX" target="_blank" rel="nofollow"><strong>was $49 now $39</strong></a></li><li><strong>Ultimate Ears WonderBoom 4: </strong><a href="https://www.amazon.com/dp/B0BRXJVG1S" target="_blank" rel="nofollow"><strong>was $99 now $69</strong></a></li><li><strong>Soundcore Boom 2: </strong><a href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><strong>was $139 now $89</strong></a></li><li><strong>Bose SoundLink Micro Portable (2nd Gen): </strong><a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow"><strong>was $129 now $109</strong></a></li><li><strong>JBL Flip 6: </strong><a href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8/ref" target="_blank" rel="nofollow"><strong>was $129 now $109</strong></a></li><li><strong>Marshall Stanmore III: </strong><a href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTF9D7F" target="_blank" rel="nofollow"><strong>was $399 now $299</strong></a><strong> </strong></li></ul><h2 class="article-body__section" id="section-best-bluetooth-speaker-deals"><span>Best Bluetooth speaker deals</span></h2><div class="product"><a data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="XnqELzjemVWDKqXxoESeBh" name="tribit-pocketgo-bluetooth-shower-speaker-e7119067-af9e-4c09-9feb-6f1f593c89d6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XnqELzjemVWDKqXxoESeBh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review" data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19">Tribit PocketGo</a> will be your new best friend. For less than $30, this Bluetooth speaker packs one heck of a punch in the sound department. On top of that, it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for long hikes in unpredictable weather. And I do mean <em>long</em> hikes because the speaker has a total battery life of 20 hours, making it ideal for a weekend camping trip. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="57ccf1d7-9b1f-4693-a430-f797ab937986" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19">View Deal</a></p></div><div class="product"><a data-dimension112="823cadc2-9ca3-4206-8c9b-aeae63897adb" data-action="Deal Block" data-label="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound. It's small enough to take traveling, and will easily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension48="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound. It's small enough to take traveling, and will easily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension25="$39" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="uQJgL3k2xaEEAQXb6mspWh" name="jbl-go-4--ultraportable-waterproof-and-d-327de61a-f398-40ce-b539-115ea309ca87.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/uQJgL3k2xaEEAQXb6mspWh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound. It's small enough to take traveling, and will easily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX" target="_blank" rel="nofollow" data-dimension112="823cadc2-9ca3-4206-8c9b-aeae63897adb" data-action="Deal Block" data-label="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound. It's small enough to take traveling, and will easily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension48="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound. It's small enough to take traveling, and will easily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension25="$39">View Deal</a></p></div><div class="product"><a data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$69" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1425px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="D7QYGUpe98kCsZkVddg4oV" name="Ultimate Ears Wonderboom 4.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/D7QYGUpe98kCsZkVddg4oV.jpg" mos="" align="middle" fullscreen="" width="1425" height="1425" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The mighty and portable Wonderboom 4 is a great outdoor speaker that goes louder than it has any right to. In our <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review" data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$69">Ultimate Ears WonderBoom 4 review</a>, our reviewer loved its compact size, very good 16-hour battery life and slick rugged looks. It's IP67 water and dust-resistant as well, so you can really take it anywhere to listen to your tunes.<a class="view-deal button" href="https://www.amazon.com/dp/B0BRXJVG1S/" target="_blank" rel="nofollow" data-dimension112="63fb91fa-8472-4a1a-878a-7988816e6615" data-action="Deal Block" data-label="Ultimate Ears WonderBoom 4 review" data-dimension48="Ultimate Ears WonderBoom 4 review" data-dimension25="$69">View Deal</a></p></div><div class="product"><a data-dimension112="a4801986-08e5-4cb3-b7c9-996fa5055660" data-action="Deal Block" data-label="I get my hands on enough Bluetooth speakers to know that a speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="I get my hands on enough Bluetooth speakers to know that a speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$89" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="3CvgYRTFMbxneUZcepKkae" name="soundcore boom 2" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/3CvgYRTFMbxneUZcepKkae.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>I get my hands on enough Bluetooth speakers to know that a speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go <em>loud</em>. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere. <a class="view-deal button" href="https://www.amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" target="_blank" rel="nofollow" data-dimension112="a4801986-08e5-4cb3-b7c9-996fa5055660" data-action="Deal Block" data-label="I get my hands on enough Bluetooth speakers to know that a speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension48="I get my hands on enough Bluetooth speakers to know that a speaker of this caliber for just $89 is unheard of. The Boom 2 has a massive 80W power, meaning it will go loud. Like the much pricier JBL options, the Boom 2 has a 24 hour battery life and IP67 rating, so it'll be able to follow you anywhere." data-dimension25="$89">View Deal</a></p></div><div class="product"><a data-dimension112="cf0750f0-bdd8-47b5-959d-4238241380b0" data-action="Deal Block" data-label="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too — however, the best discount is currently on the Black speaker." data-dimension48="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too — however, the best discount is currently on the Black speaker." data-dimension25="$109" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1105px;"><p class="vanilla-image-block" style="padding-top:110.05%;"><img id="W9bhTKNwnzv3HgRUn6A2sc" name="SoundLink Micro Portable Bluetooth Speaker (2nd Gen)" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/W9bhTKNwnzv3HgRUn6A2sc.jpg" mos="" align="middle" fullscreen="" width="1105" height="1216" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too — however, the best discount is currently on the Black speaker.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0FDLD34V5" target="_blank" rel="nofollow" data-dimension112="cf0750f0-bdd8-47b5-959d-4238241380b0" data-action="Deal Block" data-label="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too — however, the best discount is currently on the Black speaker." data-dimension48="Powerful Bose sound in a tiny package! This speaker packs a punch with crisp, bassy sound, IP67 water and dust resistance and 12 hours of battery life. The color options are stylish, too — however, the best discount is currently on the Black speaker." data-dimension25="$109">View Deal</a></p></div><div class="product"><a data-dimension112="313957f5-fbf2-4fcc-9aa0-1464b9ab102d" data-action="Deal Block" data-label="Yes — another JBL speaker. Well, that's because JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. Especially at this awesome price. It's now on sale for $109, which is an awesome deal for this pocket-sized 30W speaker. It's IP67 and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="Yes — another JBL speaker. Well, that's because JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. Especially at this awesome price. It's now on sale for $109, which is an awesome deal for this pocket-sized 30W speaker. It's IP67 and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$109" href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:120.00%;"><img id="33AJemCSzK8fNYEhkUfBtm" name="JBL Flip 6" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/33AJemCSzK8fNYEhkUfBtm.jpg" mos="" align="middle" fullscreen="" width="1000" height="1200" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Yes — another JBL speaker. Well, that's because JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. <em>Especially</em> at this awesome price. It's now on sale for $109, which is an awesome deal for this pocket-sized 30W speaker. It's IP67 and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening. <a class="view-deal button" href="https://www.amazon.com/JBL-Flip-Portable-Waterproof-Speaker/dp/B09RQ47HC8" target="_blank" rel="nofollow" data-dimension112="313957f5-fbf2-4fcc-9aa0-1464b9ab102d" data-action="Deal Block" data-label="Yes — another JBL speaker. Well, that's because JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. Especially at this awesome price. It's now on sale for $109, which is an awesome deal for this pocket-sized 30W speaker. It's IP67 and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension48="Yes — another JBL speaker. Well, that's because JBL just doesn't miss with its Bluetooth speakers. Although the Flip 7 came out earlier this year, the Flip 6 shouldn't be forgotten about. Especially at this awesome price. It's now on sale for $109, which is an awesome deal for this pocket-sized 30W speaker. It's IP67 and has a 12 hour battery life, meaning it's perfect to chuck in your backpack for all day outdoor listening." data-dimension25="$109">View Deal</a></p></div><div class="product"><a data-dimension112="f4742625-134e-49ac-92c3-a46771157668" data-action="Deal Block" data-label="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension48="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension25="$119" href="https://www.amazon.com/dp/B0D6WB7BV6/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:932px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CaY2r9G6VHX74UcMmqyGy" name="bose soundlink flex gen 2 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CaY2r9G6VHX74UcMmqyGy.jpg" mos="" align="middle" fullscreen="" width="932" height="932" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers.<a class="view-deal button" href="https://www.amazon.com/dp/B0D6WB7BV6/" target="_blank" rel="nofollow" data-dimension112="f4742625-134e-49ac-92c3-a46771157668" data-action="Deal Block" data-label="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension48="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension25="$119">View Deal</a></p></div><div class="product"><a data-dimension112="93f486a2-a5f2-431c-902c-e99df9039999" data-action="Deal Block" data-label="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension48="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension25="$159" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:60.93%;"><img id="fAV3y9WMvrAFWQKezHyaAh" name="JBL Charge 6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/fAV3y9WMvrAFWQKezHyaAh.jpg" mos="" align="middle" fullscreen="" width="1500" height="914" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNTFBNX" target="_blank" rel="nofollow" data-dimension112="93f486a2-a5f2-431c-902c-e99df9039999" data-action="Deal Block" data-label="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension48="The JBL Charge 6 is a great speaker with plenty of battery life and some great sound quality. 28 hours of staying power means the tunes will keep on coming. The color options are wicked too, letting you really show off (or blend in) as much as you want." data-dimension25="$159">View Deal</a></p></div><div class="product"><a data-dimension112="2a0cde19-24ee-40e1-bedf-a1e0af09a805" data-action="Deal Block" data-label="Bose Soundlink Home" data-dimension48="Bose Soundlink Home" data-dimension25="$189" href="https://www.amazon.com/Bose-SoundLink-Portable-Bluetooth-Bookshelf/dp/B0DT7BFNNW" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:827px;"><p class="vanilla-image-block" style="padding-top:58.65%;"><img id="b9zi7aAFzqby3DuaeGuEKX" name="SoundLink Home Speaker" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/b9zi7aAFzqby3DuaeGuEKX.png" mos="" align="middle" fullscreen="" width="827" height="485" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Our Audio Editor loves her pair of <a href="https://www.tomsguide.com/audio/bose-soundlink-home-review" data-dimension112="2a0cde19-24ee-40e1-bedf-a1e0af09a805" data-action="Deal Block" data-label="Bose Soundlink Home" data-dimension48="Bose Soundlink Home" data-dimension25="$189">Bose Soundlink Home</a> speakers thanks to their handsome looks and solid sound profile. You can connect them together for stereo mode as well. More than 9 hours of battery would be nice, though. Still, this is an excellent deal price on a lovely speaker.<a class="view-deal button" href="https://www.amazon.com/Bose-SoundLink-Portable-Bluetooth-Bookshelf/dp/B0DT7BFNNW" target="_blank" rel="nofollow" data-dimension112="2a0cde19-24ee-40e1-bedf-a1e0af09a805" data-action="Deal Block" data-label="Bose Soundlink Home" data-dimension48="Bose Soundlink Home" data-dimension25="$189">View Deal</a></p></div><div class="product"><a data-dimension112="127125be-37ad-40b3-a26e-cd8cc5eaa6e2" data-action="Deal Block" data-label="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension48="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension25="$299" href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTF9D7F" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wYnAg4Aq77FqRs4Sxa3xn7" name="marshall stanmore iii" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wYnAg4Aq77FqRs4Sxa3xn7.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire. <a class="view-deal button" href="https://www.amazon.com/Marshall-Stanmore-Bluetooth-Wireless-Speaker/dp/B09HTF9D7F" target="_blank" rel="nofollow" data-dimension112="127125be-37ad-40b3-a26e-cd8cc5eaa6e2" data-action="Deal Block" data-label="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension48="Marshall consistently makes some of the best audio gear out there, and the Stanmore III is no different. This awesome amp-lookalike speaker has a 3.5mm jack input and RCA input, so you can hook it up for even higher-quality music. The speaker has designated bass and treble dials so you can turn up the bass all the way if you so desire." data-dimension25="$299">View Deal</a></p></div><div class="product"><a data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349" href="https://www.amazon.com/dp/B0F967JT5Y" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1509px;"><p class="vanilla-image-block" style="padding-top:99.34%;"><img id="h3j5SdPPY2co2Kf2LhGvk3" name="Marshall Kilburn III.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/h3j5SdPPY2co2Kf2LhGvk3.jpg" mos="" align="middle" fullscreen="" width="1509" height="1499" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The epic-looking <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review" data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">Marshall Kilburn III</a> is more than just a pretty face — it also sounds amazing too. The battery life is extremely impressive, and the on-device tone controls make keeping the music going easier than anything else. It also, you know, looks really cool. We currently rank it as the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> you can buy.<a class="view-deal button" href="https://www.amazon.com/dp/B0F967JT5Y" target="_blank" rel="nofollow" data-dimension112="388f10b2-6d1a-4d57-835a-9edcb7a15cc5" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">View Deal</a></p></div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ JBL Xtreme 5 review: The most rugged, bassiest, and gnarliest Xtreme yet ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-5-review</link>
                                                                            <description>
                            <![CDATA[ The JBL Xtreme 5 is a worthy upgrade from the Xtreme 4, with louder, bassier sound, a new LED lightshow, and enviable clarity in the mids and highs. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">juBAcPYkd42GgorPAD2LL9</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/VGaPnKAv3dUs8X4k8hA3wZ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 24 Apr 2026 09:49:58 +0000</pubDate>                                                                                                                                <updated>Fri, 03 Jul 2026 12:44:15 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ erin.bashford@futurenet.com (Erin Bashford) ]]></author>                    <dc:creator><![CDATA[ Erin Bashford ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/rLvJvJVZx43hEzSsJy3BpL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Erin Bashford is a senior reviews writer at Tom’s Guide. She has a Master’s in Broadcast and Digital Journalism from the University of East Anglia and 7 years of experience reviewing music and events for various publications. She has edited publications such as Outline Magazine’s Guide to Norwich, and she has written for a number of music magazines and websites such as Clash Magazine, Outline Magazine and Dork Magazine. She has a strong interest in audio gear and the music world. &lt;/p&gt;&lt;p&gt;As an ex-barista, Erin is passionate about coffee tech. She also loves finding the best cooking hacks and kitchen appliances, including her beloved Instant Pot. &lt;/p&gt;&lt;p&gt;In her spare time, you can find her reading, practising yoga, hiking, writing fantasy novels, or stressing over NYT Games.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/VGaPnKAv3dUs8X4k8hA3wZ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:description>                                                            <media:text><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:text>
                                <media:title type="plain"><![CDATA[the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/VGaPnKAv3dUs8X4k8hA3wZ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The JBL Xtreme 5 is one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best</a> <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">Bluetooth speakers</a> you can buy. There you go. I’m clocking out now; you don’t need me anymore. I jest, but seriously, the JBL Xtreme 5 is a sonic <em>machine</em>. If you care about bass-heavy sound that doesn’t skimp on clarity across the mids and highs, it’s all about the Xtreme 5. </p><p>Although it’s considerably larger and heavier than its predecessor (not to mention $20 pricier), the Xtreme 5 is perfect for taking to every party on your calendar. It’s got a carry strap that alleviates as much weight as possible, an improved 28-hour battery life, and is daring enough to fill any room with its bassy sound. </p><p>If you’re a student, partygoer, or simply living room raver, let me do you a favor and put you onto the Xtreme 5. Want to find out more? Of course you do. Keep reading for the full story in this JBL Xtreme 5 review. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-specs"><span>JBL Xtreme 5 review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9" target="_blank" rel="nofollow">$399</a> / <a href="https://www.amazon.co.uk/JBL-Portable-Bluetooth-Convenient-Waterproof/dp/B0GR1RYBWW" target="_blank" rel="nofollow">£299</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, navy, camo</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>6.1 x 13.6 x 6.5 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>6.4 pounds </p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>28 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 6.0</p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>IP68</p></td></tr><tr><td class="firstcol " ><p><strong>Multi-speaker connectivity</strong></p></td><td  ><p>Auracast</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response</strong></p></td><td  ><p>40Hz - 20kHz</p></td></tr><tr><td class="firstcol " ><p><strong>Range</strong></p></td><td  ><p>~100 feet</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jbl-xtreme-5-review-price-availability"><span>JBL Xtreme 5 review: Price & availability </span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="ays7QHuqZmq9T8zMi56KZa" name="JBL_extreme_515.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/ays7QHuqZmq9T8zMi56KZa.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The JBL Xtreme 5 is a wince-inducing <a href="https://www.amazon.com/JBL-Xtreme-Waterproof-Convenient-Built/dp/B0GHYH9DN9" target="_blank" rel="nofollow">$399 from Amazon U.S.</a> and<a href="https://www.amazon.co.uk/JBL-Portable-Bluetooth-Convenient-Waterproof/dp/B0GR1RYBWW" target="_blank" rel="nofollow"> £299 from Amazon U.K.</a>. In the States, this is a price increase of $20 over the previous model, which was already expensive at $379. </p><p>In the U.K., you’re getting a better deal — and you’re actually getting a discount from the Xtreme 4. Although on JBL’s website the 5 is listed at £329, it’s £299 on Amazon (sold by Amazon, not a third party), so I’d recommend buying on Amazon. </p><p>Even for a boombox speaker such as this, $399 is really, really pricey. I have the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-blast-2-review">Tribit StormBox Blast 2</a>, $299, which is just as loud as the Xtreme 5. Although it doesn’t have as <em>much</em> clarity in the mids and treble as the Xtreme 5, it’s a fantastic, cheaper option. Even cheaper is the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet">JBL Flip 7</a> ($129). Another more affordable option is the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/soundcore-boom-2-plus-review">Soundcore Boom 2 Plus</a>, which is $249 and packs a major bass-shaped punch. </p><p>If money is no object, may I interest you in the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Marshall Bromley 450</a>? This $799 speaker is literally the size of an amp (which it can also double up as), has rave lighting, and can be a karaoke machine. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-design"><span>JBL Xtreme 5 review: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="aZgYJW4SUikecSyuNtX5Ka" name="JBL_extreme_508.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/aZgYJW4SUikecSyuNtX5Ka.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Like its predecessor, the JBL Xtreme 5 is a gorpcore delight. This rugged speaker looks like it will survive the apocalypse. In 3026, it’ll just be a few Nokia bricks and the JBL Xtreme 5 left. </p><p>However, unlike its predecessor, the Xtreme 5 is weirdly massive. It’s 2 inches longer, 0.3 inches deeper, and 1 inch taller than the Xtreme 4. The Xtreme 5 is also <em>two pounds</em> heavier than the Xtreme 4. I’m a weakling, so I’m perhaps not the best point of comparison. But if you, too, have arms built like string beans, you will probably be better off sticking with a lighter speaker like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-middleton-ii-review">Marshall Middleton II</a> $329) or opting for <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet">JBL’s uber-portable Flip 7</a> ($149).</p><p>I’m not really sure why JBL did this, because the iconic brand already has a line of bulky speakers — the <a href="https://www.amazon.com/JBL-Boombox-Waterproof-Multi-Speaker-Connection/dp/B0F1H9CTPQ">JBL Boombox 4, $549</a> — and there should be more of a distinction between each model. </p><p>You even get a nice LED light show now! The Xtreme 4 didn’t have any lights, but I’m seeing it more and more these days, even on cheaper brands like Soundcore and Tribit. You can change the lights using the JBL Portable app — I chose pink, obviously. </p><p>Last but not least: IP68. This is an upgrade over the Xtreme 4, which had an IP67 rating. IP68 basically means this is the most durable speaker physically possible. It’s completely dustproof, you can bury it in sand, and it’ll live to tell the tale, and it’s fully waterproof.</p><p>Oh, and before I forget — the Xtreme 5 is literally dropproof now, certified and everything. Remember what I said about it surviving the apocalypse? </p><h2 id="connectivity-4">Connectivity </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="Pxa5kX2RrieVaEeUz3iQ4a" name="JBL_extreme_517.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/Pxa5kX2RrieVaEeUz3iQ4a.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As you might expect from a $399 speaker, the Xtreme 5 comes pre-loaded with a litany of features. Of course, you’ve got AuraCast — the technology that allows you to sync up your speakers with as many devices as you physically can get in one room — an IP68 rating, a huge array of EQ presets (including a completely custom option), the aforementioned light show, Playtime Boost, and now USB-C lossless audio. </p><p>Playtime Boost is effectively a battery extender. It reduces the quality of music playing (even if the JBL Portable app claims it “boost[s] up sound”, which it most certainly does not) to extend your battery life — but more on that later. </p><p>Another fun feature is AuraCast. I was able to connect the Xtreme 4 with the Xtreme 5 instantly, with no connectivity issues.</p><p>The Xtreme 5 boasts Bluetooth 6.0, which is refreshing to see. Bluetooth 6.0 basically means the Xtreme 5’s range and reliability are both as high as possible. I was able to get out of my apartment and down the street before the speaker disconnected. </p><h2 id="controls-4">Controls</h2><p>The Xtreme 5 looks a treat, with a bulletproof-looking fabric grill and high-quality metal-meets-plastic carabiners. I particularly like the radiators on either side, and found myself mesmerized by their bouncing. </p><p>You can control the Xtreme 5 by tactile buttons on the top: these include play/pause, volume up, volume down, and Auracast. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-sound-quality"><span>JBL Xtreme 5 review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="qa58jc34t5nr7tYMjiNwnZ" name="JBL_extreme_509.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/qa58jc34t5nr7tYMjiNwnZ.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Alright, now let’s get into the good stuff. The Xtreme 5 sounds just as good as the Xtreme 4, with powerful, earth-tremoring bass and clarity in vocals and mids, even in bass-heavy tracks. It sounds notably better than the Tribit StormBox Blast 2, EarFun UBoom X, and the Soundcore Boom 2 Plus. </p><p>As for EQs, you can select from: ‘JBL Signature’, ‘Chill’, ‘Energetic’, ‘Vocal’, and ‘Custom’. ‘Custom’ lets you create an EQ from a 7-band frequency range. I found ‘JBL Signature’ sounded the best. </p><p>As this is a party speaker, I had to start with some party bangers. ‘Can’t Get You Out of My Head’ by Kylie Minogue sounded thrilling through the Xtreme 5; the plucky synth instrumental and keyboard motifs weren’t lost in the bass-heavy speaker. Clarity across the bass, vocals, and synth riffs was high. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="GYHVas7y6CD8EpWrLLVDFa" name="JBL_extreme_510.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/GYHVas7y6CD8EpWrLLVDFa.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>After, I kept the energy high but switched genre. ‘Flight fm’ by Joy Orbison is a UKG/jungle-inspired electronic track not afraid of starting a fight. As it’s almost entirely bass, I worried the Xtreme 5 might struggle discerning between the layers, but oh boy, was I wrong. When the beat dropped, my entire desk started shaking. The bass squelched and oozed out of the speaker, a bouncing quagmire after sucking down a few amps. </p><p>Last, I knew I had to test a lower-energy track (even though the Xtreme 5 is a party speaker first and foremost). I played ‘Kick the Curb’ by NewDad, which is a slow, shoegazey track with atmospheric acoustic guitars and breathy vocals. This sounded fantastic, despite the lack of frenetic, club-ready bass, with extreme clarity in the top of the frequency range — I could hear every rattle of the lazy tambourine, every layer of the airy vocals. </p><p>Overall, the Xtreme 5 sounds fantastic… but I knew it would. It’s just as fun and addictive as the Xtreme 4. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-app"><span>JBL Xtreme 5 review: App</span></h2><p>As with other speakers on JBL’s roster, the Xtreme 5 uses the JBL Portable app. This app is as you’d expect. User-friendly, easily navigable, not glitchy. </p><p>Here are a few screenshots so you can see for yourself. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rPjALcABggx989r2kiknwR" name="jbl screenshots xtreme 5" alt="the jbl xtreme 5 shown in the jbl portable app showing auracast partytogether, eq, and color light selection" src="https://cdn.mos.cms.futurecdn.net/rPjALcABggx989r2kiknwR.png" mos="" align="middle" fullscreen="" width="1600" height="900" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide / JBL)</span></figcaption></figure><p>I found changing my EQ and light settings to be incredibly easy, and I never struggled to figure out where each feature was hiding. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-battery-life"><span>JBL Xtreme 5 review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="cn2LcMQRJ3UG55mvFQXUxZ" name="JBL_extreme_506.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/cn2LcMQRJ3UG55mvFQXUxZ.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>While the Xtreme 5 ‘technically’ has a 24-hour battery life, you get an extra 4hours with ‘Playtime Boost’, making the overall max battery life 28 hours. This is four hours longer than the Xtreme 4 and eight hours longer than the Soundcore Boom 2 Plus, but two hours less than EarFun’s UBoom X. </p><p>This is much better than the Flip 7’s 16 hours, but not as impressive than the Boombox 4’s 34 hours. Oh, and the Boombox 4 lets you replace the battery, essentially futureproofing the speaker for years and years. If you’re serious about using your speaker to death, I’d invest more in the Boombox 4. </p><h2 class="article-body__section" id="section-jbl-xtreme-5-review-verdict"><span>JBL Xtreme 5 review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="Nw44CQNChUFixU37U852oZ" name="JBL_extreme_511.JPG" alt="the JBL Xtreme 5 bluetooth speaker in blue shown with the rugged carry strap and buttons" src="https://cdn.mos.cms.futurecdn.net/Nw44CQNChUFixU37U852oZ.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I said this about the Xtreme 4, but the Xtreme 5 may be my favorite portable(ish) speaker to date. The sound quality is fantastic, with extreme height and width and bass that’ll make your bones shake. </p><p>While yes, it’s expensive, it’s a price I’d be willing to pay for a speaker of this caliber. For house parties, pool parties, beach parties, street parties, I’m not sure you’d get much better at this price. Sure, you could spend a bit extra for the Boombox 4 or the Marshall Bromley 450, but for $400, it’s the Xtreme 5. </p><p>So if you want rich, room-filling sound and don’t mind that the Xtreme 5 is a bit bigger than its predecessor, I wholeheartedly recommend this music monster. </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I’m soundtracking my summer with the $54 JBL Go 5 — it’s one of the best budget speakers I’ve ever used ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/im-soundtracking-my-summer-with-the-usd54-jbl-go-5-its-one-of-the-best-budget-speakers-ive-ever-used</link>
                                                                            <description>
                            <![CDATA[ I've spent the last couple of weeks listening to my favorite tunes on the JBL Go 5, and here's why it's the perfect speaker for the summer. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">y5m5DyrRcDeLzfk7zMvahd</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/6gTtmYbVXuDQbax58Q6bqX-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 22 Apr 2026 08:30:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/6gTtmYbVXuDQbax58Q6bqX-1280-80.jpg">
                                                            <media:credit><![CDATA[Nikita Achanta / Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A JBL Go 5 Bluetooth speaker in blue]]></media:description>                                                            <media:text><![CDATA[A JBL Go 5 Bluetooth speaker in blue]]></media:text>
                                <media:title type="plain"><![CDATA[A JBL Go 5 Bluetooth speaker in blue]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/6gTtmYbVXuDQbax58Q6bqX-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As temperatures soar, many of us are looking forward to spending time with our friends and family outdoors, perhaps at a barbecue, or by a friend's pool.</p><p>And I don't know about you, but anytime I hang out with my friends or my partner's, we love having some jazzy tunes playing in the background. No gathering, during the summer or otherwise, is complete without one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>. </p><p>Don't have one yet? Don't fret, because I've found the finest speaker to soundtrack your summer without breaking the bank: the new <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5</a>.</p><div class="product"><a data-dimension112="596265c4-5e14-4f81-a366-5a7c5ee538a7" data-action="Deal Block" data-label="If you want a sub-$60 Bluetooth speaker to soundtrack pool parties and shower karaoke sessions, the JBL Go 5 is an excellent choice. It boasts a wide soundstage packed into a compact, portable frame. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension48="If you want a sub-$60 Bluetooth speaker to soundtrack pool parties and shower karaoke sessions, the JBL Go 5 is an excellent choice. It boasts a wide soundstage packed into a compact, portable frame. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension25="$54" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHYJ7BS9/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="YHNWrEwxj5uzgYGXCTeiJ6" name="Go5-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/YHNWrEwxj5uzgYGXCTeiJ6.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>If you want a sub-$60 Bluetooth speaker to soundtrack pool parties and shower karaoke sessions, the JBL Go 5 is an excellent choice. It boasts a wide soundstage packed into a compact, portable frame. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHYJ7BS9/" target="_blank" rel="nofollow" data-dimension112="596265c4-5e14-4f81-a366-5a7c5ee538a7" data-action="Deal Block" data-label="If you want a sub-$60 Bluetooth speaker to soundtrack pool parties and shower karaoke sessions, the JBL Go 5 is an excellent choice. It boasts a wide soundstage packed into a compact, portable frame. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension48="If you want a sub-$60 Bluetooth speaker to soundtrack pool parties and shower karaoke sessions, the JBL Go 5 is an excellent choice. It boasts a wide soundstage packed into a compact, portable frame. It looks great, sounds even better, and can be customized via a user-friendly companion app. It’s IP68-rated, so it’s highly waterproof, dustproof and drop-proof too." data-dimension25="$54">View Deal</a></p></div><p>The Go 5, in my opinion, is the ultimate summer speaker. It's extremely portable and pocketable so you can take it anywhere, and it gets very loud — perfect for large gatherings. The build quality and design are sublime, and the sound quality is nothing short of outstanding. </p><p>I've spent a couple of weeks listening to my favorite tunes on the Go 5, and I'm here to convince you to get one for yourself if you love music.</p><h2 id="take-anywhere-able">Take anywhere-able</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="brKBZu6PbKMNaVC94Df8HR" name="JBL-Go-5-op-ed-1" alt="A JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/brKBZu6PbKMNaVC94Df8HR.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Nikita Achanta / Tom's Guide)</span></figcaption></figure><p>One of the key reasons why the JBL Go 5 is the perfect summer speaker is its size — the Go 5 measures 3.98 x 3.05 x 1.7 inches and weighs just 8.16 oz. </p><div><blockquote><p>The Go 5 measures 3.98 x 3.05 x 1.7 inches and weighs just 8.16 oz.</p></blockquote></div><p>The small size and light weight make it highly portable, so whether you're taking it to a friend's house or to a beach party, you should have no problem carrying it in your backpack or pocket. It's also got a strap for clipping to a carabiner, in case you want to travel with it that way.</p><p>Even though it's compact and light, the Go 5 doesn't compromise on build quality. It's well-built, and I didn't notice any hollow-sounding parts when I tapped the speaker with my fingernails. </p><p>It looks fantastic too, sporting a minimalist design with two low-key LED lighting strips which light up to correspond with the speaker's color: If you buy the blue model, the lights will be blue, and if you buy the red model, they'll be red, and so on.</p><p>Controls on the Go 5 are extremely straightforward too, and you don't need to be tech-savvy to use the speaker — so don't worry about people at your party struggling to figure out how to adjust the volume or swap between Bluetooth sources. </p><p>Oh, and did I mention that the Go 5 is IP68-rated, so it can be submerged in 1.5m-deep water for up to 30 minutes, and it's highly dustproof <em>and </em>drop-proof? Yep, it's the ideal speaker for the outdoors.</p><h2 id="surprisingly-powerful-bass-for-such-a-tiny-speaker">Surprisingly powerful bass for such a tiny speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="8xQWveEDZmFt23B5xnXZp4" name="JBL_Go_5_Blue01.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/8xQWveEDZmFt23B5xnXZp4.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Size isn't everything, and you shouldn't underestimate just how loud the JBL Go 5 can get. For its size, it can get loud enough to soundtrack a large gathering of people and you can pair multiple Auracast-enabled speakers to it, or grab another Go 5 and pair them together instantly by simply bumping them together. It's <em>that</em> easy.</p><p>As for the sound quality, the Go 5 boasts powerful bass response and sub-bass too, something its predecessor, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-4-review">Go 4</a>, struggled with. </p><p>In songs like 'Elma' by Yin Yin and 'Loser' by Tame Impala, I appreciated the clean bass, and the fact that I could hear every string plucked on the bass guitar. The bass had plenty of low-end impact in both tracks, and the kickdrum was clean and warm too. </p><p>Of course, I couldn't feel the sub-bass in my chest as the speaker goes down to only 100Hz, it still provided a good backbone to both songs, and ensured that the tracks didn't sound hollow.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="PteE7JXPDMnDiaH7dXGnJ5" name="JBL_Go_5_Blue05.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/PteE7JXPDMnDiaH7dXGnJ5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Alongside the bass, the treble is crisp and vibrant. 'First Light' by Lana Del Rey and 'Time' by Pink Floyd sounded beautiful through the Go 5. </p><div><blockquote><p>'First Light' by Lana Del Rey and 'Time' by Pink Floyd sounded beautiful through the Go 5. </p></blockquote></div><p>The sibilance was clean, and "t" and "s" sounds didn't bleed into one another. Along the same lines, plosives didn't pop too much to detract from Lana's vocals. In my favorite song by Pink Floyd, the hi-hats and cymbal hits didn't sound too shrill and they didn't pierce through the rest of the soundstage.</p><p>Unlike the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">StormBox MIni+</a>, the Go 5 doesn't sound too tinny or distorted when it's being played at high volumes. I say "too tinny" because small speakers are limited by their hardware, and you should expect some level of tinniness at 100% volume. </p><p>Having said that, it isn't unpleasant at all. The Go 5 gets a 10/10 from me in the sound department.</p><h2 id="so-good-and-cheap-that-i-m-buying-two">So good and cheap that I'm buying two</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="eyYVkdjMHBrEWZzUHhhWF5" name="JBL_Go_5_Blue07.JPG" alt="JBL Go 5" src="https://cdn.mos.cms.futurecdn.net/eyYVkdjMHBrEWZzUHhhWF5.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The JBL Go 5 has quickly become my favorite budget Bluetooth speaker. It earned a 4.5-star rating and the coveted Editor's Choice award from me in my <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">JBL Go 5 review</a> thanks to its stellar sound quality, beautiful design, sturdy and durable build.</p><p>And it isn't a hefty investment either. The Go 5 retails for <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow">$54</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-AirTouch-Waterproof/dp/B0GPPRPRM5/" target="_blank" rel="nofollow">£39 at Amazon</a>, so even though it's $5 more expensive than its predecessor, it's well-worth the extra spend. For the price, I'd be happily buying two so that I can pair them together and create left and right stereo channels. </p><p>Not sure how to take your music with you outside in 2026? The Go 5 is, without a doubt, the perfect speaker to soundtrack your summer.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-Oq8dpW"></div>                            </div>                            <script src="https://kwizly.com/embed/Oq8dpW.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review">The JBL Go 5 is one of the best budget speakers I’ve tested, and it offers stellar sound for just $54</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/the-only-bluetooth-speaker-you-need-for-pool-parties-costs-less-than-usd40-no-im-not-joking">The only Bluetooth speaker you need for pool parties costs less than $40 — no, I’m not joking</a></li><li><a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">I've spent 300 hours testing the best portable Bluetooth speakers — these are the 11 that are worth your money</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The JBL Go 5 is one of the best budget speakers I’ve tested, and it offers stellar sound for just $54 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-5-review</link>
                                                                            <description>
                            <![CDATA[ The JBL Go 5 is a compact and budget speaker, offering refined sound quality, excellent IP68-rated durability, and it's accompanied by a user-friendly app. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VgS84gKcFw3YVZPH5trFcf</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/43m3gBP6BUwYjA2cUcBpTk-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 21 Apr 2026 14:59:19 +0000</pubDate>                                                                                                                                <updated>Tue, 09 Jun 2026 10:32:30 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/43m3gBP6BUwYjA2cUcBpTk-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Go 5 Bluetooth speaker in blue]]></media:description>                                                            <media:text><![CDATA[JBL Go 5 Bluetooth speaker in blue]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Go 5 Bluetooth speaker in blue]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/43m3gBP6BUwYjA2cUcBpTk-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As someone who loves music, I don’t think any party (or shower karaoke session) is complete without a speaker. The JBL Go 5 is one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best budget Bluetooth speakers</a> you can buy today, period. It improves on its predecessor by offering more refined sub-bass, and the overall sound quality is dynamic thanks to the wide soundstage.</p><p>The Go 5 retains most of the Go 4’s design while adding LED lighting strips. It’s highly waterproof, dustproof and even drop-proof, so it’s perfect for the outdoors. Small and compact, the Go 5 is pocketable so it’s great for your travels. Auracast-enabled, it can be paired with other JBL speakers, and creating stereo channels with another Go 5 is easy as pie too.</p><p>Should you buy it? Yes! Why? Read my full JBL Go 5 review to find out.</p><h2 class="article-body__section" id="section-jbl-go-5-review-specs"><span>JBL Go 5 review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow">$54</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-AirTouch-Waterproof/dp/B0GPPRPRM5/" target="_blank" rel="nofollow">£39</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, Blue, Pink, Purple, Red, Squad (camo), White</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>3.98 x 3.05 x 1.7 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>8.16oz</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (rated)</strong></p></td><td  ><p>10 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 6.0 with SBC, AAC and LC3</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP68</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jbl-go-5-review-price-availability"><span>JBL Go 5 review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="43m3gBP6BUwYjA2cUcBpTk" name="JBL_Go_5_Blue01.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/43m3gBP6BUwYjA2cUcBpTk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Launched in April 2026 alongside the JBL Xtreme 5, the JBL Go 5 succeeds the two-year-old <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-4-review">JBL Go 4</a>. Priced at <a href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Drop-Proof-Compatible/dp/B0GHY1H2JS/" target="_blank" rel="nofollow">$54</a> / <a href="https://www.amazon.co.uk/JBL-Ultra-Portable-Bluetooth-AirTouch-Waterproof/dp/B0GPPRPRM5/" target="_blank" rel="nofollow">£39 at Amazon</a>, it’s $5 more expensive than its predecessor, which isn’t a huge jump (and is justified by the Go 5’s improved sound). It’s available in a range of colors, including Black, Blue, Pink, Squad (camo) and White.</p><p>The Go 5 is a budget Bluetooth speaker, and it finds itself competing with the likes of the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a> ($39), the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tozo-pe1-review">Tozo PE1</a> ($39) and the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-micro-2-review">Tribit StormBox Micro 2</a> ($59). There’s no dearth of speakers in the sub-$50 range, so why should you buy the Go 5 and not, say, the StormBox Mini+, the PE1 or the Go 4 ($49)? The Go 5 is more rugged thanks to its IP68 durability rating and it boasts loud volume and better bass performance.</p><h2 class="article-body__section" id="section-jbl-go-5-review-design"><span>JBL Go 5 review: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="5STi5GRz34P2rCsgdustSk" name="JBL_Go_5_Blue05.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/5STi5GRz34P2rCsgdustSk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Compact and pocketable</strong></li><li><strong>Bluetooth 6.0 with SBC, AAC and LC3</strong></li><li><strong>IP68 waterproofing and dust resistance</strong></li></ul><p>If you put the JBL Go 5 next to the Go 4, you probably wouldn’t be able to tell the difference. The Go 5 bears striking resemblance to its predecessor as it continues to sport a boxy, rectangular design with mesh covers over the front and rear faces. The rear face, however, doesn’t feature two grip rubber strips anymore. Instead, they extend down from the top and bottom, lending the speaker a more premium look.</p><p>The base and top of the Go 5 are also fairly similar to the Go 4’s. There’s textured rubber feet at the bottom to make the Go 5 stand upright. In terms of size, the Go 5 remains pocketable and portable, measuring 3.98 x 3.05 x 1.7 inches and weighing 8.16oz. It’s a little heavier than the Go 4 which weighs 6.7oz but the difference is hardly noticeable. I’ve had no trouble carrying the speaker in my backpack, a tote bag, and even in my jacket’s pocket. The Go 5 is smaller and more portable than the Tribit StormBox Mini+, the Tribit StormBox Micro 2 and the Tozo PE1 too.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="crw28dVeL9MLPh8duqcVsk" name="JBL_Go_5_Blue09.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/crw28dVeL9MLPh8duqcVsk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>JBL has added two strips of LED lighting which run along the base and the top plate. There are four effects to choose from, within the companion app (more on that shortly): Bounce, Loop, Freeze, and Switch. You can’t change the color as the default is blue on the Blue model (red on the Red, pink on the Pink, and so on). I don’t mind that as it makes the speaker look classy. If you want customizable RGB lighting, I’d recommend the Tribit StormBox Mini+ instead.</p><h2 id="weatherproofing-3">Weatherproofing</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="dffYpLoEruCcwXDYiGUjrk" name="JBL_Go_5_Blue03.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/dffYpLoEruCcwXDYiGUjrk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you want to use the Go 5 to soundtrack a pool party, a karaoke session in the shower, or a bonfire in the Sahara, you can confidently do so as the speaker is IP68-rated. This means that the speaker can be submerged in 1.5m of water for 30 minutes, and it’s dust-proof too, so it won’t get damaged by dirt and dust. Oh, and it’s drop-proof. Although JBL doesn’t specify how much of a tumble the Go 5 can sustain, I dropped it from a height of approximately 2m onto a wooden floor and it was unscathed.</p><h2 id="controls-5">Controls</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="K4HmZzgxFYjAhW5NV8RVfk" name="JBL_Go_5_Blue07.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/K4HmZzgxFYjAhW5NV8RVfk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The playback controls (play and volume) are located on the top plate. Other buttons — power, Bluetooth and Auracast — can be found along the Go 5’s left edge. Straightforward enough that you shouldn’t have any issues getting to grips with them.</p><h2 id="connectivity-5">Connectivity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="uC2ebyiBSjyqHao9wHwDwk" name="JBL_Go_5_Blue11.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/uC2ebyiBSjyqHao9wHwDwk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Go 5 utilizes <a href="https://www.tomsguide.com/audio/bluetooth-speakers/bluetooth-60-just-revealed-heres-what-that-means-for-you">Bluetooth 6.0 </a>as opposed to its rivals utilizing older versions. Alongside support for SBC and AAC codecs which you can also find on the Go 4, the Go 5 supports LC3 for improved sound quality at lower bitrates.</p><p>Just like its predecessor, the Go 5 is Auracast-enabled which means you can link multiple speakers together for bigger sound — or if you want to play the same song in different parts of a room. Auracast pairing is simple as all you need to do is press the triangle on two (or more) Auracast-enabled speakers and et voilà. While we found the process on the Go 4 a little finicky, I had no problem pairing the Go 5 with my friend’s <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-clip-5-review">JBL Clip 5</a> ($79).</p><p>The Go 5 also features AirTouch stereo pairing if you have another Go 5 at hand, as I did. All you need to do is touch the two speakers together and left and right stereo channels are instantly created. It worked flawlessly in my testing, and considering the Go 5 doesn’t cost a lot, you might as well buy two for a more immersive experience.</p><h2 class="article-body__section" id="section-jbl-go-5-review-sound-quality"><span>JBL Go 5 review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="5Hbs8VvvABGvN7EqGfy6Tk" name="JBL_Go_5_Blue08.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/5Hbs8VvvABGvN7EqGfy6Tk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Better sub-bass than the Go 4</strong></li><li><strong>Crisp treble and refined mids</strong></li><li><strong>Can get very loud!</strong></li></ul><p>One of our complaints with the JBL Go 4 was that the sub-bass was practically non-existent, but thankfully, the JBL Go 5 doesn’t suffer from that problem. The sound quality is refined and fine-tuned and straight out of the box, it doesn’t give you much to complain about. The Go 5 can get <em>very </em>loud too, especially for the size, and it doesn’t sound tinny at high volumes either, unlike the Tozo PE1.</p><p>To test the Go 5, I listened to my range of testing songs on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, in our opinion the <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service</a> for hi-res audio. I kicked things off by listening to ‘<a href="https://open.qobuz.com/track/361933224" target="_blank" rel="nofollow">Elma</a>’ by Yin Yin, an atmospheric psychedelic rock and funk track. The Go 5 handled the track beautifully, with the shimmering guitar and synth waves boasting impressive separation. Each string plucked on the bass guitar had plenty of low-end impact. While I couldn’t feel the sub-bass in my chest due to the Go 5’s frequency response going only as low as 100Hz, it still sounded thick, warm and enjoyable.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="JSZEbTLQGjctoU4onARBuk" name="JBL_Go_5_Blue04.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/JSZEbTLQGjctoU4onARBuk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I then listened to ‘<a href="https://open.qobuz.com/album/gcsfc9y5o0or4" target="_blank" rel="nofollow">First Light</a>’ by Lana Del Rey and the song felt remarkably intimate, with Lana’s vocals shining and not getting drowned out by the David Arnold-produced orchestration. “T” and “s” sounds remained crisp without becoming hissy. The Go 5 also did an excellent job at reproducing the high-frequency tension of the string section with plenty of agility, and the song sounded energetic throughout.</p><p>‘<a href="https://open.qobuz.com/track/404364927" target="_blank" rel="nofollow">Who Will You Follow</a>' by Evanescence proved to be a good test for the Go 5’s dynamic management, as in this gothic alternative metal, Amy Lee’s vocals compete with a dense wall of sound. The Go 5 handled the distorted, low-tuned guitars with surprising grit, and the track never sounded muddy — something small speakers, like the Tribit StormBox Micro 2, can get overwhelmed by. Amy’s high-pitched vocals never pierced through the soundstage either, and they didn’t sound too shrill or unpleasant.</p><p>If you want a compact speaker that doesn’t compromise on sound quality due to its size, the Go 5 should be your port of call. It sounds better than the Tribit StormBox Mini+, a speaker I use nearly every day, and doesn’t feature poor bass reproduction like the Tribit StormBox Micro 2.</p><p><em>Listen along to my review with the JBL Go 5 testing playlist:</em></p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/62558288?zone=GB-en"></iframe><h2 class="article-body__section" id="section-jbl-go-5-review-app"><span>JBL Go 5 review: App</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="izvYppVTR5fPcXfpU87iM4" name="Go-5-app" alt="JBL Portable app on Google Pixel 10 Pro XL" src="https://cdn.mos.cms.futurecdn.net/izvYppVTR5fPcXfpU87iM4.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable"><a href='https://cdn.mos.cms.futurecdn.net/izvYppVTR5fPcXfpU87iM4.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JBL / Tom's Guide)</span></figcaption></figure><ul><li><strong>JBL Portable app on iOS and Android</strong></li><li><strong>User-friendly</strong></li><li><strong>Straightforward EQ customization</strong></li></ul><p>To customize the JBL Go 5, you’ll need to download the JBL Portable app for free on your <a href="https://apps.apple.com/gb/app/jbl-portable/id994041762" target="_blank" rel="nofollow">iOS</a> or <a href="https://play.google.com/store/apps/details?id=com.harman.ble.jbllink&hl=en_GB" target="_blank" rel="nofollow">Android</a> smartphone. Intuitive to use thanks to its clean interface, the JBL Portable app lets you update the Go 5’s firmware, customize stereo channels and group speakers together, customize the equalizer, and choose an EQ preset. That’s about it and it’s all you really need for a portable, budget speaker.</p><h2 class="article-body__section" id="section-jbl-go-5-review-battery-life"><span>JBL Go 5 review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:910px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="rsyihs3RivoHx2qe6SYuzk" name="JBL_Go_5_Blue10.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/v2/t:368,l:814,cw:910,ch:512,q:80/rsyihs3RivoHx2qe6SYuzk.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>10 hours of battery life</strong></li><li><strong>Rivals offer longer</strong></li></ul><p>According to JBL, the Go 5 offers up to 8 hours of playback time and 10 hours with Playtime Boost enabled via the app. This is a three-hour improvement over the Go 4. To test the battery life, I played the Go 5 at approximately 50% volume, and after nine hours, I was prompted to charge it. If you’re planning on soundtracking a barbecue or party, the Go 5 should last you comfortably.</p><p>It’s important to note, though, that the Go 5’s rivals offer longer battery lives — but not by much. The Tribit StormBox Mini+ lasted 13 hours in my testing; the Tribit StormBox Micro 2 nets you about 12 hours of usage; and the Tozo PE1 lasts around 15 hours at moderate volumes.</p><h2 class="article-body__section" id="section-jbl-go-5-review-verdict"><span>JBL Go 5 review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1820px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="DbWKzXLPxdUXF3Jwx7yk5m" name="JBL_Go_5_Blue12.JPG" alt="JBL Go 5 Bluetooth speaker in blue" src="https://cdn.mos.cms.futurecdn.net/DbWKzXLPxdUXF3Jwx7yk5m.jpg" mos="" align="middle" fullscreen="" width="1820" height="1024" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I’ve tested my fair share of Bluetooth speakers: the good, the bad, and the ugly. The JBL Go 5 falls into a secret fourth category: the excellent. Compact and pocketable, the Go 5 can be taken anywhere, and its robust IP68 waterproof and dustproof rating means you can use it by the pool or in the desert.</p><p>The Go 5 boasts a wide soundstage too, and while its predecessor struggled with sub-bass, the Go 5 thankfully doesn’t. The bass is meaty, especially for the size, and the treble is crisp and refined. Pairing the Go 5 with other Auracast-enabled speakers is a walk in the park, which is great for large gatherings where you want everyone to listen to the same tunes.</p><p>While the battery life isn’t <em>the </em>best, I don’t believe that should put you off from buying the Go 5. That’s a tradeoff I’m willing to make for the dynamic sound quality.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ These custom JBL speakers are the viral summer accessory of 2026 — and you can get one for $69 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/these-custom-jbl-speakers-are-the-viral-summer-accessory-of-2026-and-you-can-get-one-for-usd69</link>
                                                                            <description>
                            <![CDATA[ These speakers are incredibly popular right on social media, and it's not just about their value or audio quality. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">oc6AqBj2QqL5pwQZXsKn4D</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/8JHjb42UrSBxG5ULCaoAsU-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 13 Apr 2026 15:25:02 +0000</pubDate>                                                                                                                                <updated>Mon, 13 Apr 2026 15:58:21 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ dave.leclair@futurenet.com (Dave LeClair) ]]></author>                    <dc:creator><![CDATA[ Dave LeClair ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/fyx7qYdxPMTNBhdnMfNmaB.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Dave LeClair is the Senior News Editor for Tom&#039;s Guide, keeping his finger on the pulse of all things technology. He loves taking the complicated happenings in the tech world and explaining why they matter. Whether Apple is announcing the next big thing in the mobile space or a small startup advancing generative AI, Dave will apply his experience to help you figure out what&#039;s happening and why it&#039;s relevant to your life.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Before Tom&#039;s Guide, Dave worked for publications like PCMag, Pocket-lint, MUO, How-To Geek, Digital Trends, and others. He started writing about technology professionally for MUO in 2011 and hasn&#039;t looked back since. In addition to news, you can find reviews, how-to pieces, shopping guides, and many other types of content with Dave&#039;s name attached.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/8JHjb42UrSBxG5ULCaoAsU-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Custom speaker]]></media:description>                                                            <media:text><![CDATA[JBL Custom speaker]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Custom speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/8JHjb42UrSBxG5ULCaoAsU-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>JBL is a brand with a long tenure in the audio space. The company doesn't make the most expensive headphones and speakers, but it does offer a solid blend of value and sound quality. These solid speakers often find themselves featured on <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> lists for the powerful bass relative to the cost.</p><p>Seemingly out of nowhere, JBL's Bluetooth speakers are going viral on TikTok. And users aren't gushing about the audio quality of the company's models — it's the customizable nature of JBL's speakers that has the internet all excited. </p><div class="product"><a data-dimension112="02e3f88e-2e5b-4ff9-aa70-3d51195e98e1" data-action="Deal Block" data-label="The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. And it's fully customizable, so you can create the speaker of your dreams." data-dimension48="The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. And it's fully customizable, so you can create the speaker of your dreams." data-dimension25="$69" href="https://www.jbl.com/CLIP-5.html?iscstm_redesign=true&viewRecipeId=G3273WPG&sku=JBLCLIP5WHTAMCSTM" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:251px;"><p class="vanilla-image-block" style="padding-top:170.12%;"><img id="DDUbHzxQXGE9aFGyhqyBSk" name="image" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/DDUbHzxQXGE9aFGyhqyBSk.png" mos="" align="middle" fullscreen="" width="251" height="427" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. And it's fully customizable, so you can create the speaker of your dreams.<a class="view-deal button" href="https://www.jbl.com/CLIP-5.html?iscstm_redesign=true&viewRecipeId=G3273WPG&sku=JBLCLIP5WHTAMCSTM" target="_blank" rel="nofollow" data-dimension112="02e3f88e-2e5b-4ff9-aa70-3d51195e98e1" data-action="Deal Block" data-label="The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. And it's fully customizable, so you can create the speaker of your dreams." data-dimension48="The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. And it's fully customizable, so you can create the speaker of your dreams." data-dimension25="$69">View Deal</a></p></div><p>Instead of just offering vibrant colors, JBL lets you <a href="https://www.jbl.com/personalize.html" target="_blank" rel="nofollow">create a custom design on four of its Bluetooth speaker models</a> (and one pair of headphones).</p><h2 id="viral-jbl-bluetooth-speaker">Viral JBL Bluetooth speaker</h2><p>You can see all kinds of videos on <a href="https://www.tiktok.com/t/ZP8gkAhvD/" target="_blank">TikTok</a> of people showing off their <a href="https://www.tiktok.com/t/ZP8gk9mbG/" target="_blank">customized JBL speakers</a>. As you might expect, people are getting creative with the various models, and a hot dog-themed speaker is gaining a lot of views and engagement on TikTok. </p><p>One person even designed a bunch of speakers and <a href="https://www.tiktok.com/t/ZP8gk5dE6/" target="_blank">shared a slideshow on TikTok</a>, asking viewers to help them choose the best option. And it is a tough choice, because they all look great.</p><p>We actually looked at the now-viral speaker a few months ago for a YouTube video showcasing gifts under $100 (we chose the <a href="https://www.jbl.com/CLIP-5.html?iscstm_redesign=true&viewRecipeId=G3273WPG&sku=JBLCLIP5WHTAMCSTM" target="_blank" rel="nofollow">JBL Clip 5, which is currently on sale for $69</a>). </p><div class="youtube-video" data-nosnippet ><div class="video-aspect-box"><iframe data-lazy-priority="high" data-lazy-src="https://www.youtube-nocookie.com/embed/EU2Ck5r5a9U?start=282" allowfullscreen></iframe></div></div><p>You can also customize the <a href="https://www.jbl.com/GRIP-1.html?iscstm_redesign=true&viewRecipeId=QJQGYU7H&sku=JBLGRIPWHTCSTM" target="_blank" rel="nofollow">Grip for $129</a>, the<a href="https://www.jbl.com/FLIP-7.html?iscstm_redesign=true&viewRecipeId=C3RRECKN&sku=JBLFLIP7WHTAMCSTM" target="_blank" rel="nofollow"> Flip 7 for $144</a> and the <a href="https://www.jbl.com/CHARGE5-.html?iscstm_redesign=true&viewRecipeId=E3UQBF7X&sku=JBLCHARGE5WAMCSTM" target="_blank" rel="nofollow">Charge 5 for $169</a>. And if you're looking to make a pair of Bluetooth headphones your own, the <a href="https://www.jbl.com/TUNE520BT.html?iscstm_redesign=true&viewRecipeId=YSS2XQBZ&sku=T520BTBLKAMCSTM" target="_blank" rel="nofollow">JBL Tune 520BT is $49</a>.</p><p>As mentioned, the Clip 5 is only $69, so you don't need to break the bank to get in on the viral speaker fun. And who knows, maybe your design will be the next one to grab millions of views on TikTok, Instagram or another vertical video platform.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1420px;"><p class="vanilla-image-block" style="padding-top:59.01%;"><img id="EzLDyLfh45U8m92sR9xVHA" name="Screenshot 2026-04-13 at 11.18.56 AM" alt="Dogs on a Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/EzLDyLfh45U8m92sR9xVHA.png" mos="" align="middle" fullscreen="" width="1420" height="838" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JBL / Dave LeClair)</span></figcaption></figure><p>I think I'm going to grab the Charge 5 with a photo of my dogs, this way when I hear loud music blaring from a speaker, I can think of them barking at absolutely nothing for no reason as soon as I join an important meeting.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/wellness/fitness/of-all-the-parts-of-my-usd9-500-golf-simulator-this-usd280-hitting-mat-was-the-key-to-improving-my-game">Of all the parts of my $9,500 golf simulator, this $280 hitting mat was the key to improving my game</a></li><li><a href="https://www.tomsguide.com/home/kitchen-dining/i-put-my-ikeas-new-usd35-cast-iron-pan-head-to-head-with-my-lodge-skillet-there-was-a-clear-winner">I put IKEA's new $35 cast iron pan head-to-head with my Lodge skillet — there was a clear winner</a></li><li><a href="https://www.tomsguide.com/audio/speakers/i-tested-everything-from-a-usd100-bluetooth-speaker-to-a-usd6-000-hi-fi-setup-and-the-results-surprised-me">I tested everything from a $100 Bluetooth speaker to a $6,000 Hi-Fi setup — and the results surprised me</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living and these are my 12 top picks for outdoor listening this summer ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-these-are-my-12-top-picks-for-outdoor-listening-this-summer</link>
                                                                            <description>
                            <![CDATA[ As the weather gets warmer, these are the best Bluetooth speakers to consider for outdoor music listening. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">MCWuZdE9bSkSDsKov84Gmc</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ySJauW6NXGJH3hbvBkhaSW-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 13 Apr 2026 05:30:00 +0000</pubDate>                                                                                                                                <updated>Mon, 13 Apr 2026 14:39:47 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/ySJauW6NXGJH3hbvBkhaSW-1280-80.jpg">
                                                            <media:credit><![CDATA[Soundcore / Bose / Tribit / Ultimate Ears / JBL / Edited with Gemini]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[a composite image of the Soundcore Boom 2, Bose Soundlink Flex (2nd Gen), Tribit Stormbox Lava, Tribit PocketGo, Ultimate Ears Wonderboom 4, Ultimate Ears Everboom, Jbl Charge 6 Bluetooth speakers created using AI]]></media:description>                                                            <media:text><![CDATA[a composite image of the Soundcore Boom 2, Bose Soundlink Flex (2nd Gen), Tribit Stormbox Lava, Tribit PocketGo, Ultimate Ears Wonderboom 4, Ultimate Ears Everboom, Jbl Charge 6 Bluetooth speakers created using AI]]></media:text>
                                <media:title type="plain"><![CDATA[a composite image of the Soundcore Boom 2, Bose Soundlink Flex (2nd Gen), Tribit Stormbox Lava, Tribit PocketGo, Ultimate Ears Wonderboom 4, Ultimate Ears Everboom, Jbl Charge 6 Bluetooth speakers created using AI]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ySJauW6NXGJH3hbvBkhaSW-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>As the sun begins to show itself for the first time this year, I can't help but get excited about hanging out in the park with friends and listening to our favorite songs. I always make sure I have one of the best Bluetooth speakers on hand. </p><p>I've tested a whole host of speakers, from larger boom boxes to tiny keychain speakers you can hang on your bag, and I have my favorites. Whether it's the most balanced soundstage or the loudest sound possible, I have recommendations for anything you could possibly need. </p><p>I've gathered 12 of our highest-rated portable Bluetooth speakers that I love listening to, so you can get the best sound possible as you soak up the sun's rays as the days get longer and warmer. </p>        <div class="featured_product_block featured_block_hero" data-id="edbecd2e-faf4-4145-8b2f-f755faad4e12">            <a href="https://amazon.com/Soundcore-Subwoofer-Waterproof-Floatable-Bluetooth/dp/B0CQ53RVTW" data-model-name="Boom 2" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/FgxnpZxSjTxeAU7BaEevUd.jpg" alt="Soundcore Boom 2 by Anker, Outdoor Speaker, 80w, Subwoofer, Bassup 2.0, 24h Playtime, Ipx7 Waterproof, Floatable, Rgb Lights, Usb-C, Custom Eq, Bluetooth 5.3, Portable for Camping and Beach - Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Soundcore</div>                                        <div class="featured__title">Boom 2</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="8ee0b4a2-431b-44c1-8a4a-63325aaca2f3">            <a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0D6WD2QSQ" data-model-name="Soundlink Flex (2nd Gen)" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/UNCLaPx6GzF5io6YtjCoUe.jpg" alt="Bose Soundlink Flex Bluetooth Speaker (2nd Gen) - Portable Outdoor Speaker With Hi-Fi Audio, Waterproof and Dustproof, Usb-C, Up to 12 Hours Battery Life, Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Bose</div>                                        <div class="featured__title">Soundlink Flex (2nd Gen)</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="85d758ee-224d-475c-9b90-a3eadbfa91ba">            <a href="https://www.amazon.com/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" data-model-name="Stormbox Lava" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/9ygAsU2eyFKpFT3cKY7tee.jpg" alt="Tribit Stormbox Lava Portable Bluetooth Speaker, 80w Loud Wireless Speaker, 24h Playtime, Ip67 Waterproof, Bluetooth 5.4, Custom Eq, Xbass, Built-In Mic, Tws Pairing for Camping/beach/party/outdoor"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Tribit</div>                                        <div class="featured__title">Stormbox Lava</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="3ffeeb17-3143-468f-9ca0-9d992a76e5f5">            <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" data-model-name="PocketGo" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/DoQmihL9CScLQ7Mnoh6eMf.jpg" alt="Tribit Pocketgo Bluetooth Shower Speaker, Ip68 Waterproof/dustproof, Portable Speaker With 20h Playtime, Wireless, Bt6.0, Supports Tf Card, Electronics for Travel/outdoors/home"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Tribit</div>                                        <div class="featured__title">PocketGo</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="519508a7-7c9a-48ad-8cc8-151f97eea8b1">            <a href="https://www.amazon.com/Ultimate-Ears-WONDERBOOM-360-Degree-Waterproof/dp/B0BRXJ9WTD" data-model-name="Wonderboom 4" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/FFGFkSvRJXKRPikABUawff.jpg" alt="Ultimate Ears Wonderboom 4 Portable Waterproof Bluetooth Speaker With Big Bass and 360-Degree Sound, Dustproof Floating Speaker With 131ft (40m) Range- Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Ultimate Ears</div>                                        <div class="featured__title">Wonderboom 4</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="d0135249-d938-4de8-8267-023b8ecd0e84">            <a href="https://www.amazon.com/JBL-Waterproof-Portable-Bluetooth-Speaker/dp/B07QK2SPP7" data-model-name="Flip 5" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/6HhPj9sKxJmZTKCFckgzsf.jpg" alt="Jbl Flip 5, Waterproof Portable Bluetooth Speaker, Black, Small"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>JBL</div>                                        <div class="featured__title">Flip 5</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4da7df3c-288f-4f28-a211-c84dd97dba39">            <a href="https://www.amazon.com/JBL-Charge-Waterproof-Drop-Proof-Built/dp/B0DN2ZCZX6" data-model-name="Charge 6" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/L5Aefu6GGJjEBqMSmKWj6g.jpg" alt="Jbl Charge 6 - Portable Waterproof & Drop-Proof Bluetooth Speaker, Bold Jbl Pro Sound With Ai Sound Boost, 28hrs of Playtime, Built-In Powerbank & Comes With a Sturdy/removable Carrying Strap (black)"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>JBL</div>                                        <div class="featured__title">Charge 6</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="25774c85-bc86-4e0c-b3a9-6ac74fc3f4c9">            <a href="https://www.amazon.com/gp/aw/d/B0BYC52LYP" data-model-name="Everboom" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/7QG85qcgRWXZNUXcjPCMMg.jpg" alt="Ultimate Ears Everboom Wireless Bluetooth Portable Speaker, Big Bass and Immersive 360-Degree Sound, Floatable Waterproof Speaker Ip67, Up to 20-Hour Battery and 180 Ft (55 M) Range - Charcoal Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Ultimate Ears</div>                                        <div class="featured__title">Everboom</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="4b3eec2d-8cf6-41d4-be7c-35cc65f652b4">            <a href="https://www.amazon.com/JBL-Flip-Bluetooth-Waterproof-PartyBoost/dp/B09GJVTRNZ" data-model-name="Flip 6 " data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:56.20%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/3Yc7YQ9xuJjXSYozKnTzdg.jpg" alt="Jbl Flip 6 - Portable Bluetooth Speaker, Powerful Sound and Deep Bass, Ipx7 Waterproof, 12 Hours of Playtime, Jbl Partyboost for Multiple Speaker Pairing for Home, Outdoor and Travel (black)"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>JBL</div>                                        <div class="featured__title">Flip 6 </div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="d850f33d-f3d7-4e1b-8cb7-b63041e74efd">            <a href="https://www.amazon.com/Sonos-Roam-Portable-Waterproof-Bluetooth/dp/B0CY6TTR3C" data-model-name="Roam 2" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/SbM8ye4bPZ7vswDQD7dTrg.jpg" alt="Sonos Roam 2 - White - Portable Waterproof Bluetooth Speaker"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Sonos</div>                                        <div class="featured__title">Roam 2</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="04546449-6b50-427a-8a88-670123b714b8">            <a href="https://www.amazon.com/Tribit-StormBox-Portable-Speaker-Built/dp/B09Q59321N" data-model-name="Stormbox Micro 2 " data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/nrJ9xaPkPZQZwf3HcdkEBh.jpg" alt="Tribit Stormbox Micro 2 Wireless Portable Speaker: 10w Loud Deep Bass Sound, Ip67 Waterproof Bike Speaker With Bluetooth 5.3, 12h Playtime, Tws Pairing for Camping Travel Hiking"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Tribit</div>                                        <div class="featured__title">Stormbox Micro 2 </div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_hero" data-id="0d55249b-6e86-4b0a-b81c-bacf2ae520ae">            <a href="https://www.amazon.com/Bose-SoundLink-Bluetooth-Waterproof-Dustproof/dp/B0F7HVC62G" data-model-name="Soundlink Plus" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/umiB8PUGt7JvPecjBZKKRh.jpg" alt="Bose Soundlink Plus Portable Bluetooth Speaker, Wireless Outdoor Speaker, Up to 20 Hours Battery Life, Waterproof and Dustproof, Black"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                        <div class='featured__brand'>Bose</div>                                        <div class="featured__title">Soundlink Plus</div>                                    </div>                <div class="subtitle__description">                                                            <p></p>                </div>                            </div>        </div>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested Onkyo’s sub-$300 bookshelf speakers — and they’re the easiest way to get premium on a budget performance ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/speakers/onkyo-gx-30arc-review-amazing-sound-at-an-amazing-price</link>
                                                                            <description>
                            <![CDATA[ The Onkyo GX-30ARC bookshelf speakers offer amazing sound and versatile connectivity at a competitive price, making them a great home audio upgrade. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">UDrAahkzxuEBpeMRVALtaX</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/arvwqaMzsqmUy23eafXFgH-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 21 Mar 2026 12:00:00 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:42 +0000</updated>
                                                                                                                                            <category><![CDATA[Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/arvwqaMzsqmUy23eafXFgH-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Onkyo GX-30ARC bookshelf speakers photographed on a blue background]]></media:description>                                                            <media:text><![CDATA[Onkyo GX-30ARC bookshelf speakers photographed on a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Onkyo GX-30ARC bookshelf speakers photographed on a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/arvwqaMzsqmUy23eafXFgH-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Onkyo GX-30ARC speakers are a fantastic option for improving your home audio, and they’re some of the <a href="https://www.tomsguide.com/us/best-computer-speakers,review-6355.html">best speakers</a> you can get for the money. Their amazing sound quality and competitive price make them feel like an absolute steal. </p><p>They look great, have versatile connectivity options, and are super easy to set up. While minor, the lack of EQ customization and hi-res Bluetooth codecs like LDAC and aptX might put off wireless listeners. Even so, the GX-30ARC are bookshelf speakers at their core, so are intended to be used wired.</p><p>To find out if these are the home audio upgrades you need in your life, keep reading this full Onkyo GX-30ARC review.</p><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-cheat-sheet"><span>Onkyo GX-30ARC review: Cheat sheet</span></h2><ul><li><strong>What are they?</strong> Minimalistic bookshelf speakers with great connectivity options</li><li><strong>Who are they for?</strong> Anyone looking to make home audio upgrades</li><li><strong>What does it cost?</strong> <a href="https://www.amazon.com/Onkyo-Creator-GX-30ARC-Powered-Speakers/dp/B0DSQLNHRQ" target="_blank" rel="nofollow">$249</a> / <a href="https://www.av.com/Speakers/Onkyo-Creator-Series-GX-30ARC-Active-Bookshelf-Speakers-Pair-Black/7E22" target="_blank" rel="nofollow">£339</a></li><li><strong>What do we like?</strong> They provide amazing sound at a competitive price and are extremely easy to set up</li><li><strong>What don’t we like?</strong> No EQ alteration and only SBC</li></ul><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-specs"><span>Onkyo GX-30ARC review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Specs</strong></p></td><td  ><p><strong>Onkyo GX-30ARC</strong></p></td></tr><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Onkyo-Creator-GX-30ARC-Powered-Speakers/dp/B0DSQLNHRQ" target="_blank" rel="nofollow">$249</a> / <a href="https://www.amazon.com/Onkyo-Creator-GX-30ARC-Powered-Speakers/dp/B0DSQLNHRQ" target="_blank" rel="nofollow">$249</a></p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>8.7 x 5.8 x 6.7 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions with stand</strong></p></td><td  ><p>10.6 x 8.3 x 5.8 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>6 pounds (per speaker)</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3</p></td></tr><tr><td class="firstcol " ><p><strong>Codecs</strong></p></td><td  ><p>SBC</p></td></tr><tr><td class="firstcol " ><p><strong>Inputs</strong></p></td><td  ><p>HDMI-ARC with CEC, Bluetooth, Line analog, 3.5mm mini jack, USB-C, Optical</p></td></tr><tr><td class="firstcol " ><p><strong>Output</strong></p></td><td  ><p>RCA line for connection to subwoofer</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, White</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-price-availability"><span>Onkyo GX-30ARC review: Price & availability</span></h2><p>The Onkyo GX-30ARC are bookshelf speakers with a middle-of-the-road price point, offering amazing sound without breaking the bank. They’re available at <a href="https://www.amazon.com/Onkyo-Creator-GX-30ARC-Powered-Speakers/dp/B0DSQLNHRQ" target="_blank" rel="nofollow">Amazon U.S. for $249</a>, and at <a href="https://www.av.com/Speakers/Onkyo-Creator-Series-GX-30ARC-Active-Bookshelf-Speakers-Pair-Black/7E22" target="_blank" rel="nofollow">AV.com in the U.K. for £339</a>. </p><p>These Creator Series monitors have some pretty fierce competition, as you can get some budget bookshelf speakers with decent audio for under $10. Take the <a href="https://www.tomsguide.com/audio/speakers/majority-d40X-bookshelf-speakers-review">Majority D40X</a>, for example — they cost just $99 but still offer great sound quality and style. </p><p>Moving higher up the market, well-known budget brands like Edifier start to creep in with offerings like the <a href="https://www.tomsguide.com/audio/speakers/edifier-m60-review">Edifier M60</a>, which are compact speakers priced at $199. Or the $149 <a href="https://www.tomsguide.com/audio/speakers/edifier-r1280t-review#section-edifier-r1280t-review-price-availability">Edifier R1280T</a> speakers, which don’t have Bluetooth but are the cheapest way to get premium sound. </p><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-design-controls"><span>Onkyo GX-30ARC review: Design & controls</span></h2><p>The Onkyo GX-30ARC are some of the best-looking speakers I’ve had the pleasure of laying my eyes on. With the mesh speaker grill attached, they have a minimalistic style that complements any home interior, whether that’s next to your television, turntable, or computer. </p><p>With the speaker grill detached, the driver and tweeter are exposed, giving a more modern finish to the speaker. But the covers still protect the speaker from dust and debris, and also offer some acoustic modulation and soften the treble, although in this case it’s slight. How you set the speakers up is personal preference. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="2f9umeVGzCsywggnjNptcG" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/2f9umeVGzCsywggnjNptcG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The speakers measure 8.7 x 5.8 x 6.7 inches, which sets them at around the same size as the Majority D40X (8.8 x 5.4 x 7 inches). But with the Onkyos, you have the option to perch them on a wooden-finish plastic stand, which increases the height and depth slightly to give dimensions of 10.6 x 8.3 x 5.8 inches. Since the stand is made from plastic, it feels a little light and flimsy, which is a let down — but the effect still looks great. </p><p>You also get a speaker stand with the Edifier M60 speakers, and I wish more audio brands would include stands with bookshelf speakers. Mounting speakers at an angle like this can help to direct the music in the room for better sound. If the sound waves from the speaker are reflecting off the surface below, the sound will become dull. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3fxR9Ho8GMtYsyKqaPPRXJ" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/3fxR9Ho8GMtYsyKqaPPRXJ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fetzPS3BkFBi3jnN3v5PAJ" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/fetzPS3BkFBi3jnN3v5PAJ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Two indicator lights on the front indicate the source and the sound mode, which are visible through the grill. My only issue with the design is that the power cord is pretty short, so you’re going to want to set it up as close to a plug socket as possible.</p><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-features-connectivity"><span>Onkyo GX-30ARC review: Features & connectivity</span></h2><p>The front of the Onkyo GX-30ARC speakers is extremely minimal. You’ll find all the connectivity ports and controls on the rear of the primary speaker. Here we have the power button, inputs for all the different connectivity options, including HDMI, USB-C and Aux, and the power settings. There’s a lot more connectivity scope here than what is offered by the <a href="https://www.tomsguide.com/audio/kanto-ora4-review">Kanto Ora4</a> ($399) speakers, which are smaller and less well-equipped, but better sized and shaped for placing on a desk.</p><p>You can use the GX30ARCs as desk speakers, and they’re very good for that. But they’re a lot larger, and all of the connectivity options mean they can be used with your television or turntable. The speakers come with a remote, which is easy to use and feels well-made. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="eHsHppDzRGAES5t2zfikaG" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/eHsHppDzRGAES5t2zfikaG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The speakers use Bluetooth 5.3 and only offer the SBC audio codec. This left me a little bewildered at first since speakers like the <a href="https://www.tomsguide.com/audio/speakers/edifier-s880db-mkii-review#section-edifier-s880db-mkii-review-price-availability">Edifier S80DB MKII</a> ($499) support hi-res 24-bit streaming with LDAC. But the Onkyo GX-30ARC speakers still sound brilliant. While I would have liked to see a higher resolution codec in these speakers that look and feel so premium, their performance means it’s not the end of the world. Besides, you can use them wired for the best results anyway.</p><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-audio-quality"><span>Onkyo GX-30ARC review: Audio quality</span></h2><p>I was totally impressed by the sound of the Onkyo GX-30ARC. I tested by streaming my music over <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a> in high resolution, over Bluetooth, a 3.5mm jack, and via RCA when plugged into my turntable. </p><p>Firstly, I listened to <em>Play It Out</em> by Wolf Alice, which has powerful vocals. The speakers did a great job of bringing harmonies to the forefront of the track, without allowing the vocals to overpower the guitar-led instrumental. Every layer of the frequency range was well-rounded without overpowering the delicate sounds at the high end.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jSHtjtiiBsSiTTDUBgUAeG" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/jSHtjtiiBsSiTTDUBgUAeG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>To test out the bass performance, I listened to <em>Midnight Sun </em>by Zara Larson. This song is full of high-energy beats and impressive vocal riffs, so I was impressed to hear the speakers keeping up with the runs so easily. The bass carried well across the song and felt extremely powerful, but at the same time, the other instruments and vocals remained well-balanced. </p><p>Since you can use these speakers with your television if you want to (although you’d certainly be better off with one of the <a href="https://www.tomsguide.com/best-picks/best-cheap-soundbars">best cheap soundbars</a>), I wanted to test them out with one of my favorite movie soundtracks. I listened to <em>Planetarium </em>by Justin Hurwitz from the movie <em>La La Land, </em>an orchestral track. I was able to hear every nuance with the speakers, and their wide soundstage gave the song all the room it needed to grow. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="k8wiZS2iQBMCpscSn52vgH" name="Onkyo GX-30ARC" alt="Onkyo GX-30ARC bookshelf speakers photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/k8wiZS2iQBMCpscSn52vgH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>While there’s no personalized EQ customization with this speaker, there is a button on the controls to make the sound flat or more dynamic. This is great, as the dynamic option certainly enhances bass performance, but if you’re not in the mood for shaking floors, you can go for the flat setting. While there’s no indicator when switching between these (which would be useful), you can hear a stark difference in the settings. </p><p>I also plugged the speakers into my turntable and listened to Hayley Williams’ <em>Ego Death at a Bachelorette Party</em>. This was very easy to set up with an RAC cable, and sounded crisp — it carried the tracks with heavy distortion really well. No faults here.</p><h2 class="article-body__section" id="section-onkyo-gx-30arc-review-verdict"><span>Onkyo GX-30ARC review: Verdict</span></h2><p>The Onkyo GX-30ARC bookshelf speakers offer amazing sound quality at a competitive price. The minimalistic and sleek design means they fit into any household, and the versatile connectivity options make them perfect for anyone, whether you want to use them to listen to your records spinning or hook them up to the television. </p><p>They’re super easy to set up, but the speakers only support SBC audio, so hi-res fans will be feeling left out over wireless. That said, the sound is still stellar and you can hook the speakers up wired for high-res playback anyway. There’s very limited EQ customization, which feels like an oversight, and the stands feel cheap, but then again, they do look good. </p><p>These speakers are a great option for anyone who wants to upgrade their home audio but doesn’t want to splash major cash. And with sound this great on such a budget, they’re the perfect addition to any setup.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested the Marshall Bromley 450 and the Marshall Bromley 750 party speakers — and the winner surprised me ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-versus-marshall-bromley-750-face-off</link>
                                                                            <description>
                            <![CDATA[ I have tested both of Marshall's party speakers, and while they're very similar in terms of features, one offers better value for money. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Gf43ceDHwU3oE6nhsNhQfn</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/U6yhMyKHd6XJH4Pz2SnNBF-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 18 Mar 2026 05:45:00 +0000</pubDate>                                                                                                                                <updated>Wed, 25 Mar 2026 09:38:43 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/U6yhMyKHd6XJH4Pz2SnNBF-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Marshall Bromley 450 vs Marshall Bromley 750]]></media:description>                                                            <media:text><![CDATA[Marshall Bromley 450 vs Marshall Bromley 750]]></media:text>
                                <media:title type="plain"><![CDATA[Marshall Bromley 450 vs Marshall Bromley 750]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/U6yhMyKHd6XJH4Pz2SnNBF-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-here-are-my-top-picks-for-every-budget">best Bluetooth speakers</a> designed for parties can either elevate your group listening session or make you want to leave. You, of course, don't want the latter to happen, especially if you're the one hosting the party! Thankfully, there are plenty of options out there, and I myself have tested a few party speakers — and I have two clear favorites.</p><p>In August 2025, British giant Marshall revealed the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Bromley 750</a>, its first-ever party speaker. I reviewed it and absolutely loved it. And then came its smaller (and cheaper) sibling, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Bromley 450</a>, launched in March 2026, which I also tested and loved. Both speakers earned 4.5-star ratings from me as well as the coveted Editor's Choice award.</p><p>Testing the Bromley 450 got me thinking: "Is this better value for money than the Bromley 750?" And I even thought to myself, "Is there a clear winner here, even though they're both <em>very </em>similar to each other?" So naturally, I put them both through a five-round face-off to see which is better — and the winner surprised me. Read on to find out which party speaker is best for you.</p>        <div class="featured_product_block featured_block_versus" data-id="aed06af4-0632-4fc5-9d5d-7e938e1660b0">            <a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" data-model-name="Bromley 450" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/wVVXS5Du7Xwe7pPYGv3xVS.jpg" alt="Marshall Bromley 450"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>Marshall</div>                    <div class="featured__title">Bromley 450</div>                                    </div>                <div class="subtitle__description">                                <div class="stars__reviews"><span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="chunk rating"><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star half"></span><meta itemprop="bestRating" content="100.0" /><meta itemprop="worstRating" content="0.0" /><meta itemprop="ratingValue" content="90" /></span></div>                                        <p><p>A plethora of wired and wireless connectivity options make the Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner.</p></p>                </div>                            </div>        </div>        <div class="featured_product_block featured_block_versus" data-id="7c2350af-a6e8-40be-bc0f-9e61422e2d18">            <a href="https://www.bestbuy.com/product/marshall-bromley-750-portable-wireless-party-speaker-with-bluetooth-3-5-mm-auxiliary-rca-microphone-inputs-and-led-lights-black-brass/CFCR4H4Q6L" data-model-name="Bromley 750" data-model-brand="" ><div class='product-image-widthsetter'><p class='vanilla-image-block' data-bordeaux-image-check style='padding-top:100.00%';><img style="width: 100%" class="featured_image" src="https://cdn.mos.cms.futurecdn.net/hC3fb877MKHEkgSJ57m2nm.jpg" alt="Marshall Bromley 750"></p></div></a>            <div class="featured_product_details_wrapper">                <div class="featured_product_title_wrapper">                                                            <div class='featured__brand'>Marshall</div>                    <div class="featured__title">Bromley 750</div>                                    </div>                <div class="subtitle__description">                                <div class="stars__reviews"><span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="chunk rating"><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star"> </span><span class="icon icon-star half"></span><meta itemprop="bestRating" content="100.0" /><meta itemprop="worstRating" content="0.0" /><meta itemprop="ratingValue" content="90" /></span></div>                                        <p><p>Thanks to a huge array of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with — if you can stomach the price tag.</p></p>                </div>                            </div>        </div><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-specs"><span>Marshall Bromley 450 vs Marshall Bromley 750: Specs</span></h2><div ><table><thead><tr><th class="firstcol " ><p>Specs</p></th><th  ><p>Marshall Bromley 450</p></th><th  ><p>Marshall Bromley 750</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.marshall.com/gb/en/product/bromley-450/" target="_blank" rel="nofollow">£549</a></p></td><td  ><p><a href="https://www.bestbuy.com/product/marshall-bromley-750-portable-wireless-party-speaker-with-bluetooth-3-5-mm-auxiliary-rca-microphone-inputs-and-led-lights-black-brass/CFCR4H4Q6L" target="_blank" rel="nofollow">$1,299</a> / <a href="https://www.argos.co.uk/product/7767133/" target="_blank" rel="nofollow">£899</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black and Brass</p></td><td  ><p>Black and Brass</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>19.37 x 14.17 x 10.27 inches</p></td><td  ><p>25.7 x 16.3 x 14 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>26.89lbs</p></td><td  ><p>52.7lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response</strong></p></td><td  ><p>42Hz-20KHz</p></td><td  ><p>20Hz-20KHz</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (rated)</strong></p></td><td  ><p>40 hours</p></td><td  ><p>40 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3 with SBC, AAC and LC3, Auracast, 3.5mm jack, USB-C, RCA, 2x XLR/6.35mm combo jacks</p></td><td  ><p>Bluetooth 5.3 with SBC, AAC and LC3, Auracast, 3.5mm jack, USB-C, RCA, 2x XLR/6.35mm combo jacks</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP55</p></td><td  ><p>IP54</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-price"><span>Marshall Bromley 450 vs Marshall Bromley 750: Price</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hUxRSip2KhXanxUkyBmUuH" name="Marshall_Bromley750_ 11.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/hUxRSip2KhXanxUkyBmUuH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Marshall Bromley 450 is the smaller and cheaper sibling to the Marshall Bromley 750, so naturally, there's a bit of a price difference between the two. The Bromley 450 is available for <a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.marshall.com/gb/en/product/bromley-450/" target="_blank" rel="nofollow">£549</a> while the Bromley 750 retails for <a href="https://www.bestbuy.com/product/marshall-bromley-750-portable-wireless-party-speaker-with-bluetooth-3-5-mm-auxiliary-rca-microphone-inputs-and-led-lights-black-brass/CFCR4H4Q6L" target="_blank" rel="nofollow">$1,299</a> / <a href="https://www.argos.co.uk/product/7767133/" target="_blank" rel="nofollow">£899</a>. As neither speaker has been out for too long, we're yet to see them go on sale.</p><p>In terms of sheer value for money, the Bromley 450 is the winner. As you'll see throughout the face-off, the Bromley 450 borrows a bunch of features from its stablemate, so if you want best-in-class sound without breaking the bank, you know which way to go.</p><p><strong>Winner: </strong>Marshall Bromley 450</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-design"><span>Marshall Bromley 450 vs Marshall Bromley 750: Design</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="MmD4jwNm73MR7Xi7KzsMh3" name="Marshall_Bromley_450_edit" alt="Marshall Bromley 450" src="https://cdn.mos.cms.futurecdn.net/MmD4jwNm73MR7Xi7KzsMh3.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Both the Marshall Bromley 450 and the Marshall Bromley 750 share design philosophies, so they look fairly identical. In fact, you wouldn't be able to tell one apart from the other if you didn't already know which was which beforehand. They both feature Marshall's classic premium build quality and tasteful design with well-defined front grilles, integrated LED lamps for reactive lighting, and sleek branding in brass accents.</p><p>Controls are similar too. On both speakers, the buttons and dials look like they could belong on a guitar amp. Everything is well-signposted, and each control offers good tactile feedback when pressed or turned. While controls remain fairly similar, the Bromley 750 has an additional Sound Character dial which lets you adjust audio on a scale of Dynamic to Loud, depending on your listening style.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3CYoYoEcxdUdh2cJwmrusH" name="Marshall_Bromley750_ 7.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/3CYoYoEcxdUdh2cJwmrusH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The biggest difference between the two speakers is the size and weight. The Bromley 450 is much smaller, measuring 19.37 x 14.17 x 10.27 inches compared to the Bromley 750 measuring 25.7 x 16.3 x 14 inches. It's also lighter at 26.89 pounds, while the Bromley 750 is nearly double the weight at 52.7 pounds. But both speakers are easy to transport: the Bromley 450 features a built-in handle on its side while the Bromley 750 features large wheels and a suitcase-like pull-out handle.</p><p>Neither is better nor worse than the other, so we'll call this round a tie.</p><p><strong>Winner: </strong>Tie</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-features-connectivity"><span>Marshall Bromley 450 vs Marshall Bromley 750: Features & connectivity</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="b69nAtuE2GyrtpahGbUaQH" name="Marshall_Bromley750_ 4.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/b69nAtuE2GyrtpahGbUaQH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>There's no dearth of features and connectivity options on both the Marshall Bromley 450 and the Marshall Bromley 750. Both feature integrated LED lamps that can react and dance to the tunes you're playing to create an immersive light show. Both also feature Bluetooth 5.3 with support for SBC, AAC and LC3 codecs and multipoint connectivity for up two devices. The presence of Auracast means you can pair numerous (even endless) speakers to both — including Marshall's Bluetooth speakers, not just party ones.</p><p>The Bromley 450 and the Bromley 750 double/triple as karaoke machines and amps for instruments, as they both feature RCA and two XLR/6.35mm combo jacks each. You also get 3.5mm aux and USB-C ports for wired playback. See? A plethora of connectivity options!</p><p>While both speakers are excellent, they share a drawback too, and that's the companion app. You can't use the app to adjust the equalizer, the delay/reverb effects for karaoke and instrument use, the Sound Character (on the Bromley 750), or the lighting effects. While you can do so via physical controls, you can't via the app, which is disappointing.</p><p>Both speakers are protected against dust and water, as the Bromley 450 is IP55-rated and the Bromley 750 is IP54-rated. The former is ever-so-slightly better than the latter, and takes the win in this round by a very narrow margin.</p><p><strong>Winner: </strong>Marshall Bromley 450</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-sound-quality"><span>Marshall Bromley 450 vs Marshall Bromley 750: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="wvM8stngxrdZPYfXrpjkY3" name="Marshall_Bromley_450_edit-18" alt="Marshall Bromley 450" src="https://cdn.mos.cms.futurecdn.net/wvM8stngxrdZPYfXrpjkY3.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Marshall Bromley 450 and the Marshall Bromley 750 sound near-identical, and unless you've got a keen ear for hi-res audio or are being nit-picky, you really wouldn't notice the difference. Both speakers are well-endowed, although the Bromley 750 has more going on in terms of hardware (check out my full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Bromley 450</a> and <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Bromley 750</a> reviews to find out).</p><p>Bass on both speakers is meaty and punchy, although the Bromley 750 has more refined lower ranges as its frequency response goes down to 20Hz (versus 42Hz on the Bromley 450). On the Bromley 450, I had to increase the bass up a notch or two via the onboard dial to really appreciate the sub-bass in tracks like 'Tomorrow is Another Day' by M-High, which I didn't need to do at all on the Bromley 750.</p><p>Treble is crisp and vibrant on both speakers too. Sibilance and plosives never sound shrill or harsh or like they're bleeding into one another, as I found when listening to tracks like 'White Feather Hawk Tail Deer Hunter' by Lana Del Rey and 'From Finner' by Of Monsters and Men. I found that transitions between low and high pitches were clean on both speakers too, with the higher frequencies never sounding piercing or like they were cutting through the instrumentals.</p><p>Auracast works extremely well on both the Bromley 450 and the Bromley 750. When two speakers are synchronized and playing on opposite ends of a room, the sound is concentrated in the middle and you feel truly immersed in the music. Both speakers are phenomenal for hosting large gatherings or parties, as they get very, very loud while remaining detailed throughout the frequency range.</p><p>The Bromley 750 takes the crown in this round based purely on straight-out-of-the-box sound and its internal hardware. Thanks to the additional Sound Character dial, you get more control over the dynamics, making it the better choice of the two if you want extensive adjustment.</p><p><strong>Winner: </strong>Marshall Bromley 750</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-battery"><span>Marshall Bromley 450 vs Marshall Bromley 750: Battery</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="zYfLdMhk2avAjKXjixJdU3" name="Marshall_Bromley_450_edit-23" alt="Marshall Bromley 450" src="https://cdn.mos.cms.futurecdn.net/zYfLdMhk2avAjKXjixJdU3.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Neither the Marshall Bromley 450 nor the Marshall Bromley 750 will disappoint you when it comes to battery life. Both speakers are rated for up to 40 hours of playback between charges, which is excellent (and both upstage rivals from JBL and Soundboks). They share the same removable LiFePO4 battery pack, which can be used as power banks to charge your other devices (via a USB-C port).</p><p>In my testing, the Bromley 450's battery dipped by only 15% after six hours of listening to it at full volume. Similarly, the Bromley 750's battery dropped by 20% while listening at full volume and playing with the Sound Character over a period of seven continuous hours. This round is, once again, a tie between the two.</p><p><strong>Winner: </strong>Tie</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-verdict"><span>Marshall Bromley 450 vs Marshall Bromley 750: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="K4mGt9X2mgrM6jeTDRwaVH" name="Marshall_Bromley750_ 9.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/K4mGt9X2mgrM6jeTDRwaVH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Based on our ratings scorecard below, the Marshall Bromley 450 wins, but by a very narrow margin. The Bromley 450, in my opinion, offers better value for money over the Marshall Bromley 750. For just under $800, you get a powerful party speaker that delivers punchy bass and crisp treble, features plenty of connectivity options and controls, and slightly better waterproofing and dust protection. It's also more portable than its bigger sibling, and retains the same 40-hour battery life.</p><p>As you can see in the ratings scorecard, the Bromley 750 earns a full 25/25 points from me in the sound quality round. While the Bromley 450 is fantastic, it needs a bit of fiddling with the bass and treble dials to achieve your perfect sound (if you're being nit-picky, that is). The Bromley 750, on the other hand, doesn't require any adjustment at all, and sounds outstanding straight out of the box. The Sound Character dial gives you more control over, well, the sound too, making it more versatile.</p><p>At the end of the day, both of Marshall's party speakers are formidable and extremely competent, and neither gives you much to complain about. If I had to choose just one of the two, though, I'd go for the Bromley 450 — for its smaller size, portability and battery life.</p><h2 class="article-body__section" id="section-marshall-bromley-450-vs-marshall-bromley-750-ratings-scorecard"><span>Marshall Bromley 450 vs Marshall Bromley 750: Ratings scorecard</span></h2><div ><table><thead><tr><th class="firstcol empty" ></th><th  ><p>Marshall Bromley 450</p></th><th  ><p>Marshall Bromley 750</p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price and value (5)</strong></p></td><td  ><p>5</p></td><td  ><p>3</p></td></tr><tr><td class="firstcol " ><p><strong>Design (15)</strong></p></td><td  ><p>15</p></td><td  ><p>15</p></td></tr><tr><td class="firstcol " ><p><strong>Portability (5)</strong></p></td><td  ><p>5</p></td><td  ><p>3</p></td></tr><tr><td class="firstcol " ><p><strong>Controls (10)</strong></p></td><td  ><p>10</p></td><td  ><p>10</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity (20)</strong></p></td><td  ><p>20</p></td><td  ><p>20</p></td></tr><tr><td class="firstcol " ><p><strong>Features (10)</strong></p></td><td  ><p>8</p></td><td  ><p>8</p></td></tr><tr><td class="firstcol " ><p><strong>Sound quality (25)</strong></p></td><td  ><p>23</p></td><td  ><p>25</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (10)</strong></p></td><td  ><p>10</p></td><td  ><p>10</p></td></tr><tr><td class="firstcol " ><p><strong>Total Score (100)</strong></p></td><td  ><p>96</p></td><td  ><p>94</p></td></tr></tbody></table></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-X1A3aX"></div>                            </div>                            <script src="https://kwizly.com/embed/X1A3aX.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">I just tested Marshall’s first party speaker, and it’s perfect for musicians, karaoke enthusiasts and everyone in between</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">I’ve been testing the Marshall Bromley 450, and it might be the ‘best party speaker of 2026’</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/forget-the-bose-s1-pro-the-brand-new-marshall-bromley-450-just-redefined-party-speakers">Forget the Bose S1 Pro+ — the brand-new Marshall Bromley 450 just redefined party speakers</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Forget Bose — there's no better party speaker on the planet than the brand-new Marshall Bromley 450 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/forget-the-bose-s1-pro-the-brand-new-marshall-bromley-450-just-redefined-party-speakers</link>
                                                                            <description>
                            <![CDATA[ I've been testing the brand-new Marshall Bromley 450 party speaker. It sounds incredible and looks beautiful. It's my top pick for the party speaker of 2026. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">5UnLEb5Yw2877Lh3avGFdk</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/MmD4jwNm73MR7Xi7KzsMh3-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 17 Mar 2026 13:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/MmD4jwNm73MR7Xi7KzsMh3-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Marshall Bromley 450]]></media:description>                                                            <media:text><![CDATA[Marshall Bromley 450]]></media:text>
                                <media:title type="plain"><![CDATA[Marshall Bromley 450]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/MmD4jwNm73MR7Xi7KzsMh3-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>One thing I love about my job is that there's never a shortage of audio gear to test: When I'm listening on my own, I use the <a href="https://www.tomsguide.com/audio/headphones/marshall-monitor-iii-review">Marshall Monitor III</a> over-ear headphones. When I'm chilling with my partner or we're hanging out with friends, I turn to one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>. And if we're having a party? It's gotta be a party speaker — and there are few (if any) better than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">Marshall Bromley 450</a>.</p><p>The Bromley 450 is the British audio giant's second-ever party speaker, and it joined its bigger sibling, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Bromley 750</a>, in March 2026. I was one of the first reviewers to test the Bromley 450, and I immediately fell in love with it. It looks good, it sounds better, and its battery lasts oh-so-long. I've found it difficult to fault, really, and testing the Bromley 450 got me thinking, "Does it sound better than other party speakers in the same price range?"</p><div class="product"><a data-dimension112="8daa9b1a-d6a9-47d1-91d7-b2a175b6076c" data-action="Deal Block" data-label="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension48="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension25="$799" href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="wVVXS5Du7Xwe7pPYGv3xVS" name="Bromley-450-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/wVVXS5Du7Xwe7pPYGv3xVS.jpg" mos="" align="middle" fullscreen="" width="1000" height="1000" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner.<a class="view-deal button" href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow" data-dimension112="8daa9b1a-d6a9-47d1-91d7-b2a175b6076c" data-action="Deal Block" data-label="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension48="A plethora of wired and wireless connectivity options make the Marshall Bromley 450 not just a powerful speaker, but a stunning amp and karaoke machine as well. Music sounds glorious and highly detailed across genres, while Auracast works like a charm, and the reactive LED lighting helps with your immersion. 40-hour battery life and IP55 waterproofing make it a winner." data-dimension25="$799">View Deal</a></p></div><p>Luckily, in our testing lab, we had a Bose S1 Pro+, so I listened to it for a while and immediately knew that I preferred the Bromley 450 (sorry, Bose). There's plenty to love about the Bromley 450: from its exquisite design to the drool-worthy light show and delectable sound quality. Few brands come close to the prestige Marshall's speakers and headphones ooze, and it's no different in the case of the Bromley 450. Here's why it's my top pick for the party speaker of 2026.</p><h2 id="i-can-t-stop-staring-at-it">I can't stop staring at it</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="AJQPPonAoe5YZuUtFg5v36" name="Marshall_Bromley_450_edit-2" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/AJQPPonAoe5YZuUtFg5v36.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>When John Keats wrote "A thing of beauty is a joy forever," he was clearly talking about the Marshall Bromley 450, because I would very much like to place it in my apartment, turn on the LED lamps, and stare at it for as long as I can. It's one of the best-looking speakers I've had the pleasure of testing. No, scratch that. It's one of the best-looking <em>anything </em>I've ever used.</p><p>I'm no stranger to speakers. I've tested many during my time as a tech journalist. I've seen the good, the bad, the ugly, and the Bromley 450 very clearly belongs in the first category. It really is a thing of beauty. Its matte black finish feels exquisite to touch and pleasing to the eye, while its brass and gold accents add a premium panache to the impressive package.</p><p>Adding to the Bromley 450's appeal are its integrated LED lamps, located behind the front grille. They light up in white and yellow, and depending on the lighting mode you choose, they can dance and react to the music you're playing too, to create an immersive light and sound show. Beautiful.</p><p>I could wax poetic about the Bromley 450 all day long if I could but I wouldn't want to bore you, of course. Marshall's trademark tactile controls are present on the Bromley 450 in spades, as you can control basically every sound and light setting via the onboard buttons and dials. Thank goodness for that because the companion app is... underwhelming, at best.</p><h2 id="no-dearth-of-features">No dearth of features</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="K35X8QaEmHo99FtG6DGJt5" name="Marshall_Bromley_450_edit-9" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/K35X8QaEmHo99FtG6DGJt5.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Marshall Bromley 450 has everything you could need in a proper party speaker. Want to play music from your phone? Bluetooth 5.3 with support for SBC, AAC and LC3 codecs. Want to connect two smart devices at the same time? Multipoint connectivity. Want to plug your phone in for hi-res wired playback? 3.5mm aux or USB-C is at your disposal.</p><p>Or imagine you're hosting a party and someone says, "Hey, I brought my guitar to the party and want to serenade everyone with Oasis' Wonderwall, can I do that?" You've got the Bromley 450, so you can reply with, "My Bromley 450's got two XLR/6.35mm combo ports for guitars and RCA ports for keyboards and turntables so technically you can, but I don't want you to bore everyone with Wonderwall, so let's refrain from that." Sorry, Oasis fans, it is what it is, but at least you <em>can </em>plug your guitar into the Bromley 450 as it doubles/triples as an amp and a karaoke machine!</p><p>In addition to the connectivity options, the Bromley 450 is also protected against dust, dirt and water as it's IP55-rated, so it's perfect for outdoor parties. If you've got another Bromley 450 or 750, or even another Auracast-enabled Marshall speaker, you can sync them up any number of them to play at the same time, making the Bromley 450 even better for big parties.</p><h2 id="but-does-it-sound-good">But does it sound good?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="wvM8stngxrdZPYfXrpjkY3" name="Marshall_Bromley_450_edit-18" alt="Marshall Bromley 450" src="https://cdn.mos.cms.futurecdn.net/wvM8stngxrdZPYfXrpjkY3.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Via its onboard controls, you can adjust the Marshall Bromley 450's bass, treble, add reverb and delay effects if you're using the karaoke feature or instruments, and adjust the lighting. </p><p>"Sounds great, but does the speaker sound good?" I hear you ask, and I'm here to tell you, dear reader, that it sounds <em>excellent. </em>The sound quality really doesn't give you much to complain about, and I had to be really nit-picky to find any faults with it. And the faults I found? You'll need to play around with the bass and treble dials to get the perfect sound — but apart from that, that's about it.</p><p>The Bromley 450 is a powerful, well-endowed speaker, and you can learn all about its internal hardware in my full review. All I'm going to tell you in this article is that it sounds phenomenal. I thought the treble, especially, sounded brilliant. Crisp, vibrant, never overzealous or shrill. Sibilance and plosives gave me nothing to moan about as the sounds didn't bleed into one another, especially in tracks like 'White Feather Hawk Tail Deer Hunter' by Lana Del Rey, where she ad-libs different 's' and 'tss' sounds.</p><p>This is a party speaker, though, and chances are you'll be using it to listen to dance music or bass-heavy electronic tracks, and it's the ideal speaker for high tempo music. The bass is warm with plenty of low-end impact and detail in the mid range, and it never sounds booming in tracks like 'Tomorrow is Another Day' by M-High, and you can hear each individual string pluck in songs like 'Money' by Pink Floyd. I have no notes.</p><h2 id="unlimited-powaaaaah">Unlimited powaaaaah</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="zYfLdMhk2avAjKXjixJdU3" name="Marshall_Bromley_450_edit-23" alt="Marshall Bromley 450" src="https://cdn.mos.cms.futurecdn.net/zYfLdMhk2avAjKXjixJdU3.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The cherry on top of this beautiful cake is the Marshall Bromley 450's battery life. Marshall says that the speaker can last for up to 40 hours between charges. This will naturally depend on usage conditions, such as the LED lighting and volume. While I couldn't drain the entire battery during my testing period, I noticed that the battery had dropped by only 15% after six hours of listening to the speaker at full volume and with reactive lighting turned on. </p><p>What's even better is that you can remove the Bromley 450's battery pack (securely slotted in the back and protected by a hard plastic cover) and use it as a power bank for your other devices. It's got a USB-C port on it so you can plug in your headphones, phone or laptop. I think that's very cool, and it's something I loved about the Bromley 750 too.</p><p>I absolutely adore the Bromley 450. It's pretty, its sound quality is stunning, and it lasts a long, long time. What more could you possibly need?</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-X1ALaX"></div>                            </div>                            <script src="https://kwizly.com/embed/X1ALaX.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review">I’ve been testing the Marshall Bromley 450, and it might be the ‘best party speaker of 2026’</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-versus-marshall-bromley-750-face-off">I tested the Marshall Bromley 450 and the Marshall Bromley 750 party speakers — and the winner surprised me</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/as-a-guitarist-and-an-audiophile-this-is-the-all-in-one-speaker-ive-been-waiting-for">As a guitarist and an audiophile, this is the all-in-one speaker I’ve been waiting for</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the ‘best party speaker of 2026’ — here's why you should buy the Marshall Bromley 450 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-450-review</link>
                                                                            <description>
                            <![CDATA[ The Marshall Bromley 450 is an excellent and powerful party speaker, featuring a wide soundstage, tactile controls, and sporting a luxurious design. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">nRQ7AvEuaEcadEw4hJ5XZ8</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/WnGYtHHq6oV5ywBFiAwDSh-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 17 Mar 2026 13:00:00 +0000</pubDate>                                                                                                                                <updated>Wed, 17 Jun 2026 14:15:43 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres.&lt;/p&gt;&lt;p&gt;A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/WnGYtHHq6oV5ywBFiAwDSh-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Marshall Bromley 450 party speaker]]></media:description>                                                            <media:text><![CDATA[Marshall Bromley 450 party speaker]]></media:text>
                                <media:title type="plain"><![CDATA[Marshall Bromley 450 party speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/WnGYtHHq6oV5ywBFiAwDSh-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Seven months since the launch of its first-ever party speaker, Marshall is back with a smaller, more affordable option for the budget-conscious. The Marshall Bromley 450 is a hoot. Sporting the British giant’s trademark premium build and brass accents, the Bromley 450 is good-looking to the point that I want to keep it in my apartment as eye candy.</p><p>Aiding the Bromley 450’s position as one of the — if not <em>the </em>— best party speakers of 2026 is its wide soundstage and refined sound quality. The treble is crisp and bright; vocals are clear and detailed; and the bass is meaty and powerful, and it makes you want to headbang. With up to 40 hours of battery life, integrated reactive LED lighting, and its ability to double (or triple) as a karaoke machine and amp for your instruments, there’s so much to love about the Bromley 450.</p><p>So, is this the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> for you? Read my full Marshall Bromley 450 review to find out.</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-specs"><span>Marshall Bromley 450 review: Specs</span></h2><div ><table><thead><tr><th class="firstcol " ><p><strong>Specs</strong></p></th><th  ><p><strong>Marshall Bromley 450</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.marshall.com/gb/en/product/bromley-450/" target="_blank" rel="nofollow">£549</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black and Brass</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>19.37 x 14.17 x 10.27 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>26.89lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response</strong></p></td><td  ><p>42Hz-20KHz</p></td></tr><tr><td class="firstcol " ><p><strong>Multipoint connectivity</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Max paired devices</strong></p></td><td  ><p>2</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (rated)</strong></p></td><td  ><p>40 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3 with SBC, AAC and LC3, 3.5mm jack, USB-C, RCA, 2x XLR/6.35mm combo jacks</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP55</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-marshall-bromley-450-review-cheat-sheet"><span>Marshall Bromley 450 review: Cheat sheet</span></h2><ul><li><strong>What is it? </strong>Marshall’s second-ever party speaker, and the Bromley 750’s smaller (and cheaper) sibling</li><li><strong>Who is it for? </strong>Musicians, mobile DJs, and social gatherings or parties</li><li><strong>How much does it cost?</strong> <a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.marshall.com/gb/en/product/bromley-450/" target="_blank" rel="nofollow">£549</a>, so it’s a fair bit cheaper than the Bromley 750</li><li><strong>What do we like?</strong> The powerful bass, crisp treble, long battery life, premium design and build, and connectivity options</li><li><strong>What don’t we like? </strong>The lackluster app</li></ul><h2 class="article-body__section" id="section-marshall-bromley-450-review-price-availability"><span>Marshall Bromley 450 review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="voKAdoDGENq9nMzLmdf7jg" name="Marshall_Bromley_450_edit-2" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/voKAdoDGENq9nMzLmdf7jg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Launched on March 17 2026, the Marshall Bromley 450 is Marshall’s second-ever party speaker, and it’s the smaller and cheaper sibling to the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Bromley 750</a> ($1,299) which came out only in September 2025. The Bromley 450 is much cheaper than the Bromley 750 as it retails for <a href="https://www.amazon.com/Marshall-Bromley-Portable-Party-Speaker/dp/B0G62KZ7XD/" target="_blank" rel="nofollow">$799</a> / <a href="https://www.marshall.com/gb/en/product/bromley-450/" target="_blank" rel="nofollow">£549</a>, so it’s for anyone who wants a party speaker like the Bromley 750 but doesn’t want to burn a hole in their pocket.</p><p>The Bromley 450 is priced similarly to the JBL PartyBox 520 ($879), the Sony ULT Tower 9 ($899) and the <a href="https://www.tomsguide.com/audio/soundboks-4-review">Soundboks 4</a> ($999). In my opinion, the Bromley 450 trumps its competition with its battery life, integrated and classy LED lighting, and best-in-class sound quality.</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-design-controls"><span>Marshall Bromley 450 review: Design & controls</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="WnGYtHHq6oV5ywBFiAwDSh" name="Marshall_Bromley_450_edit" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/WnGYtHHq6oV5ywBFiAwDSh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>So good-looking and well-built</strong></li><li><strong>Convenient handle for transportation</strong></li><li><strong>Guitar amp-like tactile controls</strong></li></ul><p>Marshall knows how to make a good-looking product. I’ve been using the <a href="https://www.tomsguide.com/audio/headphones/marshall-monitor-iii-review">Marshall Monitor III</a> ($349) headphones for over a year now, and I’ve had the pleasure of listening to and testing the British brand’s other products too. Every single time, I’m blown away by the design and the build quality, and this holds true in the case of the Marshall Bromley 450 too.</p><p>Put the Bromley 450 next to its big brother, the Bromley 750, and you’ll notice that they look nearly identical. Similar to the latter, the Bromley 450 comes in matte Black with Brass accents, and the well-defined front grille houses the integrated LED lights. The side and rear drivers and passive radiators are covered with grilles as well. I love the branding on the front as it makes the speaker look premium and classy.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="Yf8yD4YyBni6XZ4KQv2prg" name="Marshall_Bromley_450_edit-15" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/Yf8yD4YyBni6XZ4KQv2prg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>But unlike the Bromley 750, the Bromley 450 isn’t as large. It measures 19.37 x 14.17 x 10.27 inches and weighs 26.89lbs, making it more portable than its stablemate. Also a departure from the Bromley 750, the Bromley 450 doesn’t feature large wheels or a suitcase-style handle that emerges from the top for easy transport. To be fair, you don’t <em>really </em>need wheels on the Bromley 450. A built-in handle is located on the speaker’s left side and it features a textured grip so that you can, well, grip your fingers around it. I had no trouble carrying the speaker up and down stairs and between different rooms.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="XwbtGmTpNXUqgU9BykKqpg" name="Marshall_Bromley_450_edit-19" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/XwbtGmTpNXUqgU9BykKqpg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Adding to the Bromley 450’s aesthetic appeal are its controls. All the buttons and dials are signposted and easy to understand. The main controls are located above the front grille and they wouldn’t look out of place on a guitar amp. Each button gives good tactile feedback when pressed, and each dial has just enough friction to ensure you don’t move it by mistake.</p><p>These buttons and dials give you plenty of control over the Bromley 450’s settings. You can adjust the volume, bass, treble, add reverb/delay if you’ve got a mic or instrument plugged in, swap between input sources, and use the M button to toggle a strobe lighting effect. The Bromley 450 doesn’t feature a Sound Character dial as found on the Bromley 750, though, but I didn’t miss it much.</p><p>Overall, the Bromley 450 is designed extremely well and hasn’t given me much to complain about. The design and controls are perfect, no notes.</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-features"><span>Marshall Bromley 450 review: Features</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="b6GQTV8sWn9SzcYFxp6G9h" name="Marshall_Bromley_450_edit-16" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/b6GQTV8sWn9SzcYFxp6G9h.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>IP55 waterproof and dustproof</strong></li><li><strong>Immersive and reactive LED lights</strong></li><li><strong>Auracast works well</strong></li></ul><p>The Marshall Bromley 450 knows how to put on a show, thanks to its integrated LED lamps. The LED lighting feels immersive and tasteful, and I much prefer it over the garish RGB lighting used by the JBL PartyBox 520.</p><p>Similar to the Bromley 750, you can choose one of three lighting modes: one ambient as well as two dynamic modes where the LED lamps react to the music playing and dance around. Reactive lighting is a delight, and it worked well to synchronize with the bass in nearly every track I played — whether that was an instrumental track or a heavy rock one.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="cnJWeSAcGPDUinix6fsB5h" name="Marshall_Bromley_450_edit-8" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/cnJWeSAcGPDUinix6fsB5h.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you want to use this speaker outside, you can do so without worrying about it getting damaged as the Bromley 450 is IP55-rated (5 for solids and 5 for liquids, on a scale of 1-8 each). It’s ever-so-slightly better than the Bromley 750’s IP54-rating — essentially, the Bromley 450 has slightly better water resistance and the same protection against dust and dirt as the 750. It’s much more durable than the JBL PartyBox 520 which is only IPX4-rated, which isn’t protected against dust at all. The Soundboks 4 has the best rating at IP65-rated, which means it has the same water protection as the Bromley 450 and better dust protection.</p><p>The Bromley 450 features Auracast (called Broadcast on Marshall devices) if you want to pair it with other speakers, and this must be done through the app. What’s great about this is that you can connect any number of Auracast-enabled speakers to the Bromley 450 — whether that’s two Bromley 450s, another Bromley 750, a <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review">Kilburn III</a> ($379) or another brand’s speaker (JBL, for instance), as proven by my testing. Sound quality is fantastic when using two Bromley 450s together, and I’ll discuss it in detail below.</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-connectivity-app"><span>Marshall Bromley 450 review: Connectivity & app</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="mcTtLM8ecXT9BEJPEzRWVg" name="Marshall_Bromley_450_edit-9" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/mcTtLM8ecXT9BEJPEzRWVg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Bluetooth 5.3 with SBC, AAC and LC3</strong></li><li><strong>Ports for wired playback, mics and instruments</strong></li><li><strong>App is still underwhelming</strong></li></ul><p>There’s no dearth of connectivity options and modes on the Marshall Bromley 450. In terms of wireless connectivity, it utilizes Bluetooth 5.3 with support for AAC, SBC and LC3 codecs. It also features multipoint connectivity so you can connect up to two devices simultaneously as I did with my <a href="https://www.tomsguide.com/phones/google-pixel-phones/google-pixel-10-pro-xl-review">Google Pixel 10 Pro XL</a> and <a href="https://www.tomsguide.com/reviews/macbook-air-2022-m2">MacBook Air M2</a>.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="TWSyRLJdeDY76YjAPRoBhg" name="Marshall_Bromley_450_edit-10" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/TWSyRLJdeDY76YjAPRoBhg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As for wired connectivity, you get 3.5mm aux and USB-C ports, as well as two XLR/6.35mm combo ports for microphones and acoustic/electric guitars, and RCA ports for keyboards and turntables. This makes the Bromley 450 perfect for mobile DJs and musicians too, as it essentially doubles as an amp and a karaoke machine. Combine that with the reverb and delay effects and you’ve got a winner.</p><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/qCZfnLdweXRAL5Zgj4Rje4.jpg" alt="Marshall Bromley 450 app screenshots" /><figcaption><small role="credit">Marshall</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/dpJ4qJUkrHfxQ2iJANSLg4.jpg" alt="Marshall Bromley 450 app screenshots" /><figcaption><small role="credit">Marshall</small></figcaption></figure></figure><p>My biggest criticism of the Bromley 450, however, is related to its app, because aside from the lackluster companion app, the speaker is great hardware-wise. The speaker uses the <a href="https://www.marshall.com/gb/en/support/speakers/learn/app-marshall-bluetooth" target="_blank" rel="nofollow">same companion app</a> as Marshall’s headphones and the Bromley 750 and just like with the Bromley 750, you don’t really get much control over the Bromley 450.</p><p>See, you can’t adjust the equalizer, the delay/reverb effects, or much of the lighting. While these controls are available onboard in the form of physical buttons and dials, what if you’re the host and on the other side of the large room it’s in? It’s a missed opportunity and it’s something I wish Marshall had fixed this time around. Third time’s the charm?</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-sound-quality"><span>Marshall Bromley 450 review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="GPUsru22LkzoKu9gYzK7eg" name="Marshall_Bromley_450_edit-5" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/GPUsru22LkzoKu9gYzK7eg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Supremely powerful bass and crisp treble</strong></li><li><strong>Broadcast works extremely well</strong></li><li><strong>Gets very, very loud</strong></li></ul><p>If you want a loud speaker to soundtrack large gatherings or for a jam session in the skatepark, I can’t recommend the Marshall Bromley 450. Don’t underestimate how loud it can get just because it’s smaller than the Marshall Bromley 750. Just like its stablemate, the Bromley 450 is well-endowed, featuring a 500W Class D amplification powered by two 90W woofers, two 55W full-range drivers, and four 50W tweeters. In terms of drivers, it is fitted with two 6.5-inch 40W woofers, four 2-inch 6W full-range drivers, and two 8-inch passive radiators.</p><p>All of this is to say that the Bromley 450 gets <em>very </em>loud and delivers best-in-class sound on par with the Bromley 750. To test the speaker, I listened to my favorite tracks on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a> which is the <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service</a> for hi-res audio. Not only did I thoroughly enjoy listening to music through the Bromley 450, I also appreciated the fact that songs sounded just as detailed when the speaker was playing at full volume and I was standing far away from it outdoors (at the opposite end of our office’s parking lot).</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="Bow3vQm5JAzcMxrNtCuD9h" name="Marshall_Bromley_450_edit-4" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/Bow3vQm5JAzcMxrNtCuD9h.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I started off by listening to ‘<a href="https://open.qobuz.com/track/53051835" target="_blank" rel="nofollow">My Dark Disquiet</a>’ by Poets of the Fall to test the bass, first and foremost, and how well the Bromley 450 creates an atmospheric soundscape — and it excels at both. Through the Bromley 450, the bassline sounded powerful with plenty of low-end impact, and it never sounded muddy or lost in the background. The throbbing bassline created a perfect backbone for the song, while the kick drum delivered some punchy flavor and worked in conjunction with the bass. Marko Saaresto’s vocals sounded as beautiful as ever.</p><p>Towards the end of the track when his voice sounds like it’s being played through a megaphone before the guitar’s staccato riffs and the drums kick in, the transition sounded seamless through the Bromley 450, and I never heard any unpleasant distortion. Keeping in line with the fact that this song features in the video game <a href="https://www.tomsguide.com/reviews/control">Control</a>, it certainly made me feel like Jesse Faden navigating the Oldest House!</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vJxAWpdpuMmoEjLUwfuNSh" name="Marshall_Bromley_450_edit-18" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/vJxAWpdpuMmoEjLUwfuNSh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1152" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I then put the Bromley 450 through a vocal stress test by listening to ‘<a href="https://open.qobuz.com/track/119828234" target="_blank" rel="nofollow">From Finner</a>’ by Of Monsters and Men. The dual lead vocalists, Nanna and Ragnar, have distinct voices: the former has an airy high pitch while the latter focuses more on the warmer lower range. Through the Bromley 450, both of them sounded harmonious, and the speaker highlighted the dual-input vocal architecture as the star of the show.</p><p>When the “heys” and “la-la-las” kicked in during the chorus, it felt like the Bromley 450 had expanded them, showcasing the speaker’s wide soundstage, and it created a sense of the song being sung on a ship in the middle of the ocean. Vocals were packed with detail too, as I could hear the wobble in Nanna’s voice every now and then. Very atmospheric, and nothing short of stunning.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="2C9vFgcF8gCuqVUqyB6DHh" name="Marshall_Bromley_450_edit-21" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/2C9vFgcF8gCuqVUqyB6DHh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Broadcast feature on the Bromley 450 works extremely well too. To test the Bromley 450’s stereo sound, I paired it with another Bromley 450 that my colleague was testing. I talked about the ease of doing so in the section above, so I’ll talk about the sound quality now.</p><p>Immediately, I noticed that the sub-bass and mid-bass sounded incredible and when I stood between the two units, I felt immersed by the tunes and felt like the bass was running through me. Vocals fared just as well if not better, with the sibilance and plosives sounded very clean and detailed in ‘<a href="https://open.qobuz.com/album/wf8u00mjina44" target="_blank" rel="nofollow">White Feather Hawk Tail Deer Hunter</a>’ by Lana Del Rey, and her words didn’t bleed into one another either. It felt like I was at a live concert.</p><p>But of course, this is a party speaker, so I had to put on a party track. I listened to ‘<a href="https://open.qobuz.com/track/232175365" target="_blank" rel="nofollow">Tomorrow is Another Day</a>’ by M-High. The bass felt mighty but so did the treble. The snare hits and hi-hats in the track never sounded shrill, and there was a distinct sound to each without bleeding into one another. This created a swing that felt mechanically perfect yet bouncy, and the synth stabs around the 3-minute mark sounded chirpy but light enough that they didn’t pierce through the rest of the instruments.</p><p><em>Listen along to my review with the Marshall Bromley 450 testing playlist:</em></p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/60154098?zone=GB-en"></iframe><h2 class="article-body__section" id="section-marshall-bromley-450-review-battery-life"><span>Marshall Bromley 450 review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="TcgSSv4jiJzEYFUvq9wpWg" name="Marshall_Bromley_450_edit-12" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/TcgSSv4jiJzEYFUvq9wpWg.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>40 hours of battery life</strong></li><li><strong>Same battery life as Bromley 750</strong></li><li><strong>Battery pack doubles as power bank</strong></li></ul><p>To top it all off, the Marshall Bromley 450 boasts outstanding battery life. It utilizes the same battery pack you’ll find in the Marshall Bromley 750, and on a single charge, both speakers can last for up to 40 hours (depending on usage conditions). I really appreciate Marshall fitting both its party speakers with the same battery despite the price difference.</p><p>The Bromley 450’s 40-hour battery life upstages the JBL PartyBox 520’s 15-hour and the Sony ULT Tower 9’s 25-hour batteries. The Soundboks 40 is rated for 40 hours on paper but our testing showed that this drops significantly, to just six hours, at high volumes. Having used the Bromley 450 for a six-hour listening session at varying volumes and the LED lighting turned on, the battery life dropped by just 15%.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="juQzAMmkGkU3zQweVEe6Fh" name="Marshall_Bromley_450_edit-22" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/juQzAMmkGkU3zQweVEe6Fh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As is the nature of the LiFePO4 battery pack that the Bromley 450 and the Bromley 750 use, it’s replaceable and can be removed by opening up the hard plastic latch on the back. It also doubles as a power bank so you can use it to charge your phone, tablet, laptop, or as I did, my Marshall Monitor III, thanks to the USB-C port.</p><h2 class="article-body__section" id="section-marshall-bromley-450-review-verdict"><span>Marshall Bromley 450 review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2048px;"><p class="vanilla-image-block" style="padding-top:56.15%;"><img id="ZogCiGRV4tZzJmXqCf3bCh" name="Marshall_Bromley_450_edit-13" alt="Marshall Bromley 450 party speaker" src="https://cdn.mos.cms.futurecdn.net/ZogCiGRV4tZzJmXqCf3bCh.jpg" mos="" align="middle" fullscreen="" width="2048" height="1150" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As party speakers go, the Marshall Bromley 450 is the best you can buy. I’d even argue that it’s better than its bigger sibling, the Bromley 750, simply because it doesn’t carry an eye-watering price tag. While the app could be better, that’s really the only issue I have with the Bromley 450 because aside from that, it’s almost perfect.</p><p>The Bromley 450 looks stunning with its matte black finish and brass accents on its buttons and dials, and the integrated LED lighting is mesmerizing. Thanks to the many connectivity options, it’s the only speaker you’ll need if you’re a mobile DJ, karaoke enthusiast, musician or even just an audiophile. Sound quality is top-notch with meaty bass and vibrant treble to boot.</p><p>If you don’t mind the underwhelming app, I can’t recommend the Bromley 450 enough. It’s great-looking, it sounds even better, and its LED lamps will leave you mesmerized if the sound hasn’t done so already.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ Sonos’ new portable speaker leaks early at Best Buy — here’s what we know ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/sonos-new-portable-speaker-leaks-early-at-best-buy-heres-what-we-know</link>
                                                                            <description>
                            <![CDATA[ Soon, the Sonos family of portable speakers will gain a new member — the top-secret Sonos Play. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">exAjPBF7uN3qstGm236QcF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/oS4tBArqb7xdvfonrhvzGc-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 02 Mar 2026 17:13:00 +0000</pubDate>                                                                                                                                <updated>Mon, 02 Mar 2026 17:28:37 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ Nick.Pino@futurenet.com (Nick Pino) ]]></author>                    <dc:creator><![CDATA[ Nick Pino ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/7xnnEdyK5eEbDVbS5pYB54.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nick Pino heads up the TV and AV verticals at Tom&#039;s Guide and covers everything from OLED TVs to the latest wireless headphones. He&#039;s a Level 1 Certified THX Home Theater Professional, and has attended classes on TV and audio calibration. On Tom&#039;s Guide, he looks after some of the site&#039;s important buying guides like the best TVs, best OLED TVs, best 4K TVs, so most of his day is spent watching and evaluating new screens from LG, Samsung, Sony, Hisense, TCL and Vizio. (And yes, he knows how lucky he is to say that.) He was formerly the Senior Editor, TV and AV at TechRadar (Tom&#039;s Guide&#039;s sister site) and has previously written for GamesRadar, Official Xbox Magazine, PC Gamer and other outlets over the last decade. He got his start on Best Buy&#039;s official video game magazine, @GAMER, for whom he attended his first E3 in 2013. He&#039;s served as a judge for CES&#039; prestigious Innovation Awards and has attended the tech conference in Las Vegas since 2014. He has a computer science degree from the University at Buffalo and still resides in the Buffalo area. (Go Bills!) Not sure which TV you should buy? Drop him an email or tweet him on Twitter and he can help you out.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/oS4tBArqb7xdvfonrhvzGc-1280-80.jpg">
                                                            <media:credit><![CDATA[The Verge]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Sonos Play Bluetooth speaker photo from a Best Buy listing.]]></media:description>                                                            <media:text><![CDATA[The Sonos Play Bluetooth speaker photo from a Best Buy listing.]]></media:text>
                                <media:title type="plain"><![CDATA[The Sonos Play Bluetooth speaker photo from a Best Buy listing.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/oS4tBArqb7xdvfonrhvzGc-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Soon, the Sonos family of portable speakers will gain a new member — the top-secret Sonos Play. Rumors have been circulating about the new device for months, but the product finally leaked on a Best Buy page over this past weekend.</p><p>The posting was spotted by <a href="https://www.theverge.com/tech/887220/sonos-play-leak" target="_blank" rel="nofollow">The Verge</a> and was quickly taken down. Before it came down, however, the outlet recorded some of its key features — including a 24-hour battery life, IP67 water resistance, AUX input, wireless charging base and support for AirPlay 2. </p><p>The listing cited a release date of March 31, though that could just be a placeholder until the speaker gets formally announced by Sonos sometime this month.</p><h2 id="meet-sonos-new-slightly-more-affordable-bluetooth-speaker">Meet Sonos’ new slightly more affordable Bluetooth speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1333px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="oS4tBArqb7xdvfonrhvzGc" name="Sonos Play Leak" alt="The Sonos Play Bluetooth speaker photo from a Best Buy listing." src="https://cdn.mos.cms.futurecdn.net/oS4tBArqb7xdvfonrhvzGc.jpg" mos="" align="middle" fullscreen="" width="1333" height="750" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: The Verge)</span></figcaption></figure><p>Based on its purported price of $399 CAD (around $290), the Sonos Play will sit in between the cheaper <a href="https://www.tomsguide.com/audio/bluetooth-speakers/sonos-roam-2-review"><u>Sonos Roam 2</u></a> ($179) and the more expensive <a href="https://www.tomsguide.com/reviews/sonos-move-2"><u>Sonos Move 2</u></a> ($499). </p><p>Its specs also seem to support its middle-of-the-road placement. At 24 hours of battery life, it would offer twice as much juice as the Roam 2 but, based on the photos, it wouldn't be as heavy duty as the 6.6 pound Move 2. The Move 2 and Roam 2 are two of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>, so you can understand why there's so much interest in the forthcoming Sonos Play.</p><p>There’s a good chance that Sonos will launch the new Play portable speaker with a refreshed version of its app. According to <a href="https://www.bloomberg.com/news/articles/2026-02-24/sonos-plans-another-app-revamp-everything-we-should-have-done-the-first-time?embedded-checkout=true" target="_blank" rel="nofollow">Bloomberg</a>, a new version of the beleaguered app is in development and already available internally. The timing appears to match up with this speaker’s end-of-month launch date.</p><p>We’ll of course reach out to Sonos for comment on its potential upcoming product launches, but we expect to hear more closer to the end of March rather than at the beginning.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/airpods/you-could-buy-airpods-pro-3-right-now-but-here-are-three-other-options-you-should-consider-instead">You could buy AirPods Pro 3 right now — but here are three other options you should consider instead</a></li><li><a href="https://www.tomsguide.com/audio/soundbars/bose-smart-soundbar-vs-polk-audio-signa-s4-which-mid-range-soundbar-is-for-you">Should you prioritize a subwoofer or smart features? I put my favorite Bose and Polk Audio soundbars head-to-head, and the results will surprise you</a></li><li><a href="https://www.tomsguide.com/audio/earbuds/im-only-excited-about-one-pair-of-upcoming-earbuds-and-its-not-the-airpods-pro-3">I'm only excited about one pair of upcoming earbuds, and it's not the AirPods Pro 3</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested everything from a $100 Bluetooth speaker to a $6,000 Hi-Fi setup — and the results surprised me ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/speakers/i-tested-everything-from-a-usd100-bluetooth-speaker-to-a-usd6-000-hi-fi-setup-and-the-results-surprised-me</link>
                                                                            <description>
                            <![CDATA[ I've always wondered — when compared one after the other, how do the many different ways to listen to music at home sound? ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">JQxiBtUxyWQNxwkBX26vVZ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/7teXGcTNGA62gziXJV2qPa-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 28 Feb 2026 10:30:00 +0000</pubDate>                                                                                                                                <updated>Wed, 29 Apr 2026 13:24:24 +0000</updated>
                                                                                                                                            <category><![CDATA[Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                                                                                    <dc:creator><![CDATA[ Tammy Rogers ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/n8MswK9ZvXC9mSb5incU44.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Tammy&#039;s reviews and buying guide expertise have more focus than ever on Tom&#039;s Guide, helping buyers find the audio gear that works best for them. Tammy has worked with some of the most desirable audio brands on the planet in her time writing about headphones, speakers, and more, bringing a consumer focussed approach to critique and buying advice. Away from her desk, you&#039;ll probably find her in the countryside writing (extremely bad) poetry, or putting her screenwriting Masters to good use creating screenplays that&#039;ll never see the light of day.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/7teXGcTNGA62gziXJV2qPa-1280-80.jpg">
                                                            <media:credit><![CDATA[Ultimate Ears]]></media:credit>
                                                                                                                                                                                                                                                                                                                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/7teXGcTNGA62gziXJV2qPa-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Audio can be cheap. Audio can also be <em>extremely expensive. </em>Thankfully its possible to spend more for incremental improvements in your audio quality. But I've always wanted to compare them all side by side — how much better does spending more sound?</p><p>So I've lined up 5 different "tiers" of audio: a cheap Bluetooth speaker, a more expensive option, a pair of Wi-Fi speakers, a budget HiFi system, and then a fairly expensive system. </p><p>I've listened to them all and now I can say which one might be worth your hard-earned money... and which ones are not. So let's get<em> </em>listening<em>.</em></p><h2 id="tier-one-cheap-bluetooth-speaker">Tier one — cheap Bluetooth speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6N95XkqCaksFC2Ftw9VpiD" name="UE Wonderboom 4" alt="UE Wonderboom product shot" src="https://cdn.mos.cms.futurecdn.net/6N95XkqCaksFC2Ftw9VpiD.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>This lil' guy is the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review">Wonderboom 4</a>, and it's one of the best ways to listen to music outdoors or in your bedroom without spending too much money. It only comes in at around $100, making it one of the cheaper Bluetooth speakers. </p><p>Can you expect the best sound? Of course not. But if you're on a budget or want a throwaway speaker for some outdoor trips, it's great.</p><p>You can listen to your music, as I did, and you won't find a huge amount to complain about. It would be nice to have some more bass, a bit more detail, and a wider soundstage, but you can't expect much from something that you can palm with one hand.</p><p>It marks the start of my audio journey, and it shows you don't have to spend loads of money to get something that sounds good. Still, I'm excited for my next speaker to see how things improve.</p><div class="product"><a data-dimension112="f44920e8-f655-416e-8c0b-dffdc541997a" data-action="Deal Block" data-label="This little speaker is a perfect portable companion that doesn't break the bank. It's got plenty of volume for your camping trips, and it's waterproof should it start to rain. It's no endgame audio experience, but it's a great way to listen to music without using headphones." data-dimension48="This little speaker is a perfect portable companion that doesn't break the bank. It's got plenty of volume for your camping trips, and it's waterproof should it start to rain. It's no endgame audio experience, but it's a great way to listen to music without using headphones." data-dimension25="$79" href="https://www.amazon.com/dp/B0BRXJ9WTD/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:679px;"><p class="vanilla-image-block" style="padding-top:138.14%;"><img id="ktGMqcBpQXhRvo5RbGM7aV" name="Wonder boom" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/ktGMqcBpQXhRvo5RbGM7aV.jpg" mos="" align="middle" fullscreen="" width="679" height="938" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This little speaker is a perfect portable companion that doesn't break the bank. It's got plenty of volume for your camping trips, and it's waterproof should it start to rain. It's no endgame audio experience, but it's a great way to listen to music without using headphones.<a class="view-deal button" href="https://www.amazon.com/dp/B0BRXJ9WTD/" target="_blank" rel="nofollow" data-dimension112="f44920e8-f655-416e-8c0b-dffdc541997a" data-action="Deal Block" data-label="This little speaker is a perfect portable companion that doesn't break the bank. It's got plenty of volume for your camping trips, and it's waterproof should it start to rain. It's no endgame audio experience, but it's a great way to listen to music without using headphones." data-dimension48="This little speaker is a perfect portable companion that doesn't break the bank. It's got plenty of volume for your camping trips, and it's waterproof should it start to rain. It's no endgame audio experience, but it's a great way to listen to music without using headphones." data-dimension25="$79">View Deal</a></p></div><h2 id="tier-2-bluetooth-stereo-pair">Tier 2: Bluetooth stereo pair</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="V9kvvCheAR548PVyszfoFd" name="Bose SoundLink Flex 2" alt="Bose SoundLink Flex 2" src="https://cdn.mos.cms.futurecdn.net/V9kvvCheAR548PVyszfoFd.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>My next port of call was to connect two Bluetooth speakers and see how much better the sound would be. I stepped up to the <a href="https://www.tomsguide.com/audio/bose-soundlink-flex-2-review">Bose SoundLink Flex 2</a>, a solid Bluetooth speaker in its own right, that also lets you double up for twice the sound.</p><p>First off, you won't get more detail or even drastically improved sound when it comes to dynamics or frequency representation. The only thing that might seem enhanced is bass volume, and that's only because there are now two drivers making the low stuff, although even then, it mostly only smooths things out. After all, there's less work for each to do.</p><p>What is on offer, however, is vastly improved soundstage. That's because you can now spread the sound out amongst the two speakers, widening the sound stage. The sound is improved in terms of space and immersion as a result — if you can afford the extra for a pair of speakers, I'd say it's actually worth buying two for stereo mode rather than one more expensive model. This next step has been an interesting one, but now I'm ready for the next step — and we're connecting to the Wi-Fi.</p><div class="product"><a data-dimension112="232dd698-8b14-48b9-9daa-60e24374a5ff" data-action="Deal Block" data-label="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension48="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension25="$119" href="https://www.amazon.com/dp/B0D6WB7BV6/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:932px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="CaY2r9G6VHX74UcMmqyGy" name="bose soundlink flex gen 2 deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/CaY2r9G6VHX74UcMmqyGy.jpg" mos="" align="middle" fullscreen="" width="932" height="932" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers.<a class="view-deal button" href="https://www.amazon.com/dp/B0D6WB7BV6/" target="_blank" rel="nofollow" data-dimension112="232dd698-8b14-48b9-9daa-60e24374a5ff" data-action="Deal Block" data-label="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension48="This Bluetooth speaker is a hefty sound step up over the WonderBoom 4, but it also offers stereo listening. Connect two for a much better sound that also features a much wider soundstage, more akin to a HiFi system and its seperate speakers." data-dimension25="$119">View Deal</a></p></div><h2 id="tier-3-wi-fi-connected-speaker">Tier 3: Wi-Fi connected speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4031px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="4Uer8g4ZXgHdjjUPTFvZ6a" name="Sonos_Era 300_in white (2).jpg" alt="Sonos Era 300 in white" src="https://cdn.mos.cms.futurecdn.net/4Uer8g4ZXgHdjjUPTFvZ6a.jpg" mos="" align="middle" fullscreen="" width="4031" height="2268" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This hourglass-shaped wierdo is the Sonos Era 300. It's a Wi-Fi-connected smart speaker that offers something we've not yet seen on the list (and won't see again) — Dolby Atmos and Spatial Audio. That means that compatible streams from Apple Music and Amazon Music sound more spacious, as if you've got multiple speakers dotted around the room.</p><p>That's why I chose this speaker. The Dolby Atmos and Spatial Audio mean that not only does the speaker sound excellent, but it also sounds much larger than similar devices sound on their own.</p><p>This step-up in audio quality does feel like it's worth the extra dollars. Its mighty bass, impressive mids, and massive sound make up for the lacking detail — and its sculpture like design makes sure it fits in no matter where you put it. Now — onto the really good stuff.</p><div class="product"><a data-dimension112="5ea81537-52d7-43df-a8b4-8f021c47bf0d" data-action="Deal Block" data-label="The Era 300 is the best speaker that Sonos makes right now, thanks to its excellent Dolby Atmos experience and top-notch sound quality. You can also use them as surrounds for a Sonos home theater system, which is pretty cool." data-dimension48="The Era 300 is the best speaker that Sonos makes right now, thanks to its excellent Dolby Atmos experience and top-notch sound quality. You can also use them as surrounds for a Sonos home theater system, which is pretty cool." data-dimension25="$479" href="https://www.amazon.com/dp/B0BW2LV57K/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:120.00%;"><img id="4Exg4MNuvptKtBpH8vsYfS" name="Sonos Era 300" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/4Exg4MNuvptKtBpH8vsYfS.jpg" mos="" align="middle" fullscreen="" width="1000" height="1200" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Era 300 is the best speaker that Sonos makes right now, thanks to its excellent Dolby Atmos experience and top-notch sound quality. You can also use them as surrounds for a Sonos home theater system, which is pretty cool.<a class="view-deal button" href="https://www.amazon.com/dp/B0BW2LV57K/" target="_blank" rel="nofollow" data-dimension112="5ea81537-52d7-43df-a8b4-8f021c47bf0d" data-action="Deal Block" data-label="The Era 300 is the best speaker that Sonos makes right now, thanks to its excellent Dolby Atmos experience and top-notch sound quality. You can also use them as surrounds for a Sonos home theater system, which is pretty cool." data-dimension48="The Era 300 is the best speaker that Sonos makes right now, thanks to its excellent Dolby Atmos experience and top-notch sound quality. You can also use them as surrounds for a Sonos home theater system, which is pretty cool." data-dimension25="$479">View Deal</a></p></div><h2 id="tier-4-entry-level-hifi">Tier 4: Entry level HiFi</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="f9CaqqBuzFKpkE7rXRtBNB" name="Wiim Amp Pro-11" alt="Wiim Amp Pro" src="https://cdn.mos.cms.futurecdn.net/f9CaqqBuzFKpkE7rXRtBNB.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>HiFi systems this side of the pond are expensive. Where in the likes of the U.K. you can pick up excellent components for relatively cheap, audio equipment in the U.S. often demands a hefty premium. Still, it's possible to spend less than $1,000 and get something that sounds epic. Case in point — the Wiim Amp Pro and a pair of Q Acoustics 3020i.</p><p>So far, this one's the clear winner. The speakers themselves have more drive, more dynamism, and more detail than the other options we've seen so far. They're more articulate as well, so you're in for a more involving musical experience. </p><p>The system is also more flexible. There are loads of inputs on the back of the amplifier, so you can hook up stuff like the <a href="https://www.tomsguide.com/best-picks/best-record-players">best record players</a> and spin some discs, or even pick up a CD player for some '90s throwback headbang sessions.</p><p>This is the happy medium for me — and even better if you can find some components on eBay and save some money. That's how I got my first HiFi system, and I only shelved some of those components when I replaced them last year. My old speakers lasted about 10 years in my care before I upgraded them, and they were older than that when I bought them.</p><p>Still, there's better; let's give it a try.</p><div class="product"><a data-dimension112="d2154a73-f367-4974-900e-2027f756f112" data-action="Deal Block" data-label="This powerful little amp isn't particularly expensive and comes packed with all the streaming stuff you'll need to get started. Just plug in your speakers, and away you go." data-dimension48="This powerful little amp isn't particularly expensive and comes packed with all the streaming stuff you'll need to get started. Just plug in your speakers, and away you go." data-dimension25="$322.15" href="https://www.amazon.com/dp/B0DFPJ91ZX/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="PvLumZqBqe3YCcSvBjgXo7" name="Amp Pro" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/PvLumZqBqe3YCcSvBjgXo7.png" mos="" align="middle" fullscreen="" width="1500" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This powerful little amp isn't particularly expensive and comes packed with all the streaming stuff you'll need to get started. Just plug in your speakers, and away you go.<a class="view-deal button" href="https://www.amazon.com/dp/B0DFPJ91ZX/" target="_blank" rel="nofollow" data-dimension112="d2154a73-f367-4974-900e-2027f756f112" data-action="Deal Block" data-label="This powerful little amp isn't particularly expensive and comes packed with all the streaming stuff you'll need to get started. Just plug in your speakers, and away you go." data-dimension48="This powerful little amp isn't particularly expensive and comes packed with all the streaming stuff you'll need to get started. Just plug in your speakers, and away you go." data-dimension25="$322.15">View Deal</a></p></div><div class="product"><a data-dimension112="6e080831-daf2-492f-a912-f7df0c8e1523" data-action="Deal Block" data-label="These bookshelf speakers pack a serious sonic punch, but don't need all that much power to drive. They've got plenty of bass extension, but proper bass heads will want to invest in an extra subwoofer for the really low stuff." data-dimension48="These bookshelf speakers pack a serious sonic punch, but don't need all that much power to drive. They've got plenty of bass extension, but proper bass heads will want to invest in an extra subwoofer for the really low stuff." data-dimension25="$479" href="https://www.amazon.com/dp/B07C4WT392/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1084px;"><p class="vanilla-image-block" style="padding-top:66.61%;"><img id="qehfwabXS9vCZYr4ZrxAAG" name="3020i" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qehfwabXS9vCZYr4ZrxAAG.png" mos="" align="middle" fullscreen="" width="1084" height="722" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>These bookshelf speakers pack a serious sonic punch, but don't need all that much power to drive. They've got plenty of bass extension, but proper bass heads will want to invest in an extra subwoofer for the really low stuff.<a class="view-deal button" href="https://www.amazon.com/dp/B07C4WT392/" target="_blank" rel="nofollow" data-dimension112="6e080831-daf2-492f-a912-f7df0c8e1523" data-action="Deal Block" data-label="These bookshelf speakers pack a serious sonic punch, but don't need all that much power to drive. They've got plenty of bass extension, but proper bass heads will want to invest in an extra subwoofer for the really low stuff." data-dimension48="These bookshelf speakers pack a serious sonic punch, but don't need all that much power to drive. They've got plenty of bass extension, but proper bass heads will want to invest in an extra subwoofer for the really low stuff." data-dimension25="$479">View Deal</a></p></div><h2 id="tier-5-premium-hifi">Tier 5: Premium HiFi</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:2000px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Y5fsurKNtAmuVdVJAMY2dD" name="Cambridge EVO 150 SE" alt="Cambridge EVO 150 SE" src="https://cdn.mos.cms.futurecdn.net/Y5fsurKNtAmuVdVJAMY2dD.jpg" mos="" align="middle" fullscreen="" width="2000" height="1125" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Now we're into the big leagues. I've got here a <a href="https://www.tomsguide.com/audio/speakers/i-just-tested-this-all-in-one-music-streaming-amplifier-and-i-want-to-put-one-in-every-room-in-my-house">Cambridge Evo 150 SE</a>, nearly three-and-a-half grand worth of streaming amplifier. At its core, it's the same idea as the Wiim Amp Pro above, but dials up all its features to eleven. That means 150 watts per channel so that it can drive even the most demanding of speakers, and some seriously impressive internals to make sure the music sent to the speakers sounds epic.</p><p>I've paired it with some monster new floorstanders from Dali, the Sonik 7. They exude special, from their monolith-like design to the massive speaker units that dominate their front fascia. They also happen to sound <em>insane.</em></p><p>As you might expect, the sound fills the living room. There's bass for days, detail for miles, and immersion like nothing else. Is it <em>that </em>much better than the entry-level system? Oh yes, it really is, but I'm not sure I could ever tell anyone to buy it.</p><p>This is an audio system for people with more money than sense. For audiophiles who are seeking the best sound possible, who have lots of money but not the tens of thousands of dollars for the <em>really </em>expensive stuff.</p><p>This is the point when things get trickier. The sound is much better than anything else on the list, but spending more becomes a case of diminishing returns. For some, this is an endgame system. Until they experience something even better, and suddenly, nothing is good enough. The path of the audiophile is a slippery, expensive slope.</p><div class="product"><a data-dimension112="5db77349-e38d-4e22-9135-ec216b15930d" data-action="Deal Block" data-label="150 Watts per channel for monster speakers, and a glorious big screen to show you what you're listening to. It sounds amazing and gets the best out of some of the most impressive speakers around — there's little more you could ask for." data-dimension48="150 Watts per channel for monster speakers, and a glorious big screen to show you what you're listening to. It sounds amazing and gets the best out of some of the most impressive speakers around — there's little more you could ask for." data-dimension25="$3299" href="https://www.amazon.com/dp/B0FCG3KD8G/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1484px;"><p class="vanilla-image-block" style="padding-top:29.51%;"><img id="hibqBFfik36dSXF4Cuj4fH" name="Evo 150 SE" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/hibqBFfik36dSXF4Cuj4fH.png" mos="" align="middle" fullscreen="" width="1484" height="438" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>150 Watts per channel for monster speakers, and a glorious big screen to show you what you're listening to. It sounds amazing and gets the best out of some of the most impressive speakers around — there's little more you could ask for.<a class="view-deal button" href="https://www.amazon.com/dp/B0FCG3KD8G/" target="_blank" rel="nofollow" data-dimension112="5db77349-e38d-4e22-9135-ec216b15930d" data-action="Deal Block" data-label="150 Watts per channel for monster speakers, and a glorious big screen to show you what you're listening to. It sounds amazing and gets the best out of some of the most impressive speakers around — there's little more you could ask for." data-dimension48="150 Watts per channel for monster speakers, and a glorious big screen to show you what you're listening to. It sounds amazing and gets the best out of some of the most impressive speakers around — there's little more you could ask for." data-dimension25="$3299">View Deal</a></p></div><div class="product"><a data-dimension112="26b21cb7-8e0e-41d3-aecd-7fc7de0e4404" data-action="Deal Block" data-label="These brand new speakers from Dali are superb. They sound monumental thanks to their impressive driver array and their hybrid tweeter setup. Yes, some speakers cost even more — but these are some seriously good pieces of audio equipment." data-dimension48="These brand new speakers from Dali are superb. They sound monumental thanks to their impressive driver array and their hybrid tweeter setup. Yes, some speakers cost even more — but these are some seriously good pieces of audio equipment." data-dimension25="$2800" href="https://www.crutchfield.com/S-uVSFmNIEHMm/p_700SNK7WN/DALI-SONIK-7-Walnut.html" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3000px;"><p class="vanilla-image-block" style="padding-top:65.00%;"><img id="GLNi4nWRRFHfVYsyNpUzrb" name="Sonik 7" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/GLNi4nWRRFHfVYsyNpUzrb.png" mos="" align="middle" fullscreen="" width="3000" height="1950" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>These brand new speakers from Dali are superb. They sound monumental thanks to their impressive driver array and their hybrid tweeter setup. Yes, some speakers cost even more — but these are some seriously good pieces of audio equipment.<a class="view-deal button" href="https://www.crutchfield.com/S-uVSFmNIEHMm/p_700SNK7WN/DALI-SONIK-7-Walnut.html" target="_blank" rel="nofollow" data-dimension112="26b21cb7-8e0e-41d3-aecd-7fc7de0e4404" data-action="Deal Block" data-label="These brand new speakers from Dali are superb. They sound monumental thanks to their impressive driver array and their hybrid tweeter setup. Yes, some speakers cost even more — but these are some seriously good pieces of audio equipment." data-dimension48="These brand new speakers from Dali are superb. They sound monumental thanks to their impressive driver array and their hybrid tweeter setup. Yes, some speakers cost even more — but these are some seriously good pieces of audio equipment." data-dimension25="$2800">View Deal</a></p></div><h2 id="which-should-you-buy">Which should you buy?</h2><p>Honestly? Buy what you can afford, or save up for that which you can't. Not everyone is going to the need the sonic prowess of even the entry level HiFi system, and will be more than happy with the $100 Bluetooth speaker.</p><p>As for what provides the best bang for your buck, I'd say the entry level HiFi system. It sounds much better than the other options towards the cheaper end of the list. You'll be left with space to upgrade in the future, and have something to show off when friends come to visit. Some of them, like the system I've built here, can be plugged into a TV to improve your movie and TV show sound.</p><p>Most important of all is to have fun — the important thing is the music you're listening to, not the equipment you're playing it through.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/kitchen-dining/i-put-my-ikeas-new-usd35-cast-iron-pan-head-to-head-with-my-lodge-skillet-there-was-a-clear-winner">I put IKEA's new $35 cast iron pan head-to-head with my Lodge skillet — there was a clear winner</a></li><li><a href="https://www.tomsguide.com/phones/samsung-phones/i-spent-24-hours-with-the-galaxy-s26-ultra-what-i-like-and-dont-so-far">I spent 24 hours with the Galaxy S26 Ultra — what I like (and don’t) so far</a></li><li><a href="https://www.tomsguide.com/sales-events/pokemon-fans-everywhere-these-are-the-pokemon-30th-anniversary-deals-you-cant-miss">41 Pokémon deals to celebrate Pokémon Day, picked by a lifelong fan</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I love doing karaoke in the shower — and these top-rated waterproof Bluetooth speakers are up to the challenge ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-love-doing-karaoke-in-the-shower-and-these-top-rated-waterproof-bluetooth-speakers-are-up-to-the-challenge</link>
                                                                            <description>
                            <![CDATA[ If, like me, you enjoy listening and singing along to music, you need a great waterproof Bluetooth speaker, and I've rounded up my top-rated favorites. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">azLTBYhSRMqDZzxGvFSioR</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qYWS3ZaqVJJmeNrkwdn8XV-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Mon, 23 Feb 2026 08:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/qYWS3ZaqVJJmeNrkwdn8XV-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Clip 5 and Tribit StormBox Mini+]]></media:description>                                                            <media:text><![CDATA[JBL Clip 5 and Tribit StormBox Mini+]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Clip 5 and Tribit StormBox Mini+]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qYWS3ZaqVJJmeNrkwdn8XV-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've loved music for as long as I can remember. My earliest memories of music involve me sitting in the backseat of my dad's car, and singing along to songs like '<a href="https://open.qobuz.com/track/172443631" target="_blank" rel="nofollow">Eleanor Rigby</a>' by The Beatles, '<a href="https://open.qobuz.com/track/15765443" target="_blank" rel="nofollow">A Horse With No Name</a>' by America, and '<a href="https://open.qobuz.com/track/47683849" target="_blank" rel="nofollow">Comfortably Numb</a>' by Pink Floyd. My love of music and singing along grew exponentially as I grew up, to the point that I was the lead vocalist of my high school band.</p><p>Though I'm a lead vocalist no longer, I still love singing, whether that's at a karaoke bar after a few drinks or performing a full-blown concert in the shower (yes, accompanied by air guitars and air drums). But to make that happen, I need one of the <a href="https://www.tomsguide.com/best-picks/best-waterproof-speakers">best waterproof Bluetooth speakers</a> that won't get ruined by steam or splashes of water. </p><p>Since joining Tom's Guide almost two years ago, I've tested my fair share of waterproof speakers, so if you're on the hunt for one, I'm here to assist. I've picked my top-rated speakers which are waterproof and in some cases, dustproof too — and they start at as low as $39!</p><h2 id="a-quick-rundown-of-ip-ratings">A quick rundown of IP ratings</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3t2GoY7HeivGV8JtBNc6Lj" name="JBL_Clip5_04.JPG" alt="A black JBL Clip 5 portable Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/3t2GoY7HeivGV8JtBNc6Lj.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>A device's, or speaker's (in this case), durability is defined by an IP score. "IP" stands for Ingress Protection, and it's the level of protection against dust and water getting in. The first number that follows "IP" determines the speaker's protection against dust, and it's measured on a scale of 1-6, with 1 being least protected and 6 being most protected.</p><p>Another number then follows the first, and the second number after "IP" represents water protection. This is measured on a scale of 1-8, with 1 being least protected and 8 being most protected. If you want to use a speaker in the shower or by the poolside, I'd recommend either an IP54 or an IP67 speaker, as you'll soon see below. One of the following recommendations is rated IPX7, which means it's waterproof but not protected against dust — but that's the bare minimum you'll want in a waterproof speaker.</p><p><em>For a more detailed breakdown of IP ratings, check out our </em><a href="https://www.tomsguide.com/best-picks/best-waterproof-speakers"><em>best waterproof Bluetooth speakers buying guide</em></a><em>.</em></p><h3 class="article-body__section" id="section-my-top-picks-for-shower-proof-speakers"><span>My top picks for shower-proof speakers</span></h3><h2 id="the-cute-speaker-with-reactive-rgb">The cute speaker with reactive RGB</h2><div class="product"><a data-dimension112="7d9d690c-b7f5-4e65-ae19-ccdd37730bb3" data-action="Deal Block" data-label="Tribit StormBox Mini+ review" data-dimension48="Tribit StormBox Mini+ review" data-dimension25="$29" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1480px;"><p class="vanilla-image-block" style="padding-top:101.35%;"><img id="iRvkqAH3YBcTTf4zRa7AdC" name="Tribit-StormBox-Mini-Plus-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/iRvkqAH3YBcTTf4zRa7AdC.jpg" mos="" align="middle" fullscreen="" width="1480" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit StormBox Mini+ is one of the finest speakers I’ve had the pleasure of testing — especially for the price. Retailing for just $39, it boasts powerful bass response and detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing so it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound.</p><p><em><strong>Read my full </strong></em><a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review" data-dimension112="7d9d690c-b7f5-4e65-ae19-ccdd37730bb3" data-action="Deal Block" data-label="Tribit StormBox Mini+ review" data-dimension48="Tribit StormBox Mini+ review" data-dimension25="$29"><em><strong>Tribit StormBox Mini+ review</strong></em></a><em><strong>.</strong></em><a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow" data-dimension112="7d9d690c-b7f5-4e65-ae19-ccdd37730bb3" data-action="Deal Block" data-label="Tribit StormBox Mini+ review" data-dimension48="Tribit StormBox Mini+ review" data-dimension25="$29">View Deal</a></p></div><h2 id="the-hook-it-anywhere-speaker">The 'hook-it-anywhere' speaker</h2><div class="product"><a data-dimension112="05e9ac61-2b80-4e49-b9da-0de9e0cbd7fa" data-action="Deal Block" data-label="JBL Clip 5 review" data-dimension48="JBL Clip 5 review" data-dimension25="$59" href="https://www.amazon.com/JBL-Clip-Ultra-Portable-Waterproof-Integrated/dp/B0CTP1XHBX/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1080px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="FpsKdgqVwp4Hb2LzfgbLrn" name="JBL Clip 5.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/FpsKdgqVwp4Hb2LzfgbLrn.jpg" mos="" align="middle" fullscreen="" width="1080" height="1080" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Clip 5 is a great Bluetooth speaker that’s truly portable, thanks to a clip that lets you hook it onto an array of things, and it boasts excellent sound quality. It's available in an array of fun colors. IP67 durability means it's fully waterproof and dustproof, so it's perfect to use poolside or in the shower.</p><p><em><strong>Read my full </strong></em><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-clip-5-review" data-dimension112="05e9ac61-2b80-4e49-b9da-0de9e0cbd7fa" data-action="Deal Block" data-label="JBL Clip 5 review" data-dimension48="JBL Clip 5 review" data-dimension25="$59"><em><strong>JBL Clip 5 review</strong></em></a><em><strong>.</strong></em><a class="view-deal button" href="https://www.amazon.com/JBL-Clip-Ultra-Portable-Waterproof-Integrated/dp/B0CTP1XHBX/" target="_blank" rel="nofollow" data-dimension112="05e9ac61-2b80-4e49-b9da-0de9e0cbd7fa" data-action="Deal Block" data-label="JBL Clip 5 review" data-dimension48="JBL Clip 5 review" data-dimension25="$59">View Deal</a></p></div><h2 id="the-inconspicuous-lowkey-speaker">The inconspicuous, lowkey speaker</h2><div class="product"><a data-dimension112="98bd3b4c-6ff8-41a2-b060-9d5b274af674" data-action="Deal Block" data-label="EarFun UBoom L review" data-dimension48="EarFun UBoom L review" data-dimension25="$59" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1115px;"><p class="vanilla-image-block" style="padding-top:49.42%;"><img id="U4eB79RfdkjMCrjY6xNuFm" name="EarFun-UBoomL-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/U4eB79RfdkjMCrjY6xNuFm.png" mos="" align="middle" fullscreen="" width="1115" height="551" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The EarFun UBoom L offers big sound on a budget. This portable speaker produces powerful bass, clear vocals and well-balanced sound across a range of genres. With a dedicated outdoor mode and an IP67 resistance rating, the speaker can soundtrack pool parties and hikes, it’s got great battery life, and the customizable EQ via the user-friendly companion app works really well.</p><p><em><strong>Read my full </strong></em><a href="https://www.tomsguide.com/audio/speakers/bluetooth-speakers/earfun-uboom-l-review" data-dimension112="98bd3b4c-6ff8-41a2-b060-9d5b274af674" data-action="Deal Block" data-label="EarFun UBoom L review" data-dimension48="EarFun UBoom L review" data-dimension25="$59"><em><strong>EarFun UBoom L review</strong></em></a><em><strong>.</strong></em><a class="view-deal button" href="https://www.amazon.com/Bluetooth-EarFun-Portable-Waterproof-Dustproof/dp/B0B1PJ5SQ7/" target="_blank" rel="nofollow" data-dimension112="98bd3b4c-6ff8-41a2-b060-9d5b274af674" data-action="Deal Block" data-label="EarFun UBoom L review" data-dimension48="EarFun UBoom L review" data-dimension25="$59">View Deal</a></p></div><h2 id="the-more-than-a-pretty-face-speaker">The 'more-than-a-pretty-face' speaker</h2><div class="product"><a data-dimension112="7c4ce2e6-cc16-49eb-b3bc-47ad5b9134d5" data-action="Deal Block" data-label="E" data-dimension48="E" data-dimension25="$129" href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1455px;"><p class="vanilla-image-block" style="padding-top:68.93%;"><img id="7xLfZrA2tj28PzCnqnP5HY" name="ES60-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/7xLfZrA2tj28PzCnqnP5HY.jpg" mos="" align="middle" fullscreen="" width="1455" height="1003" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass too.</p><p><em><strong>Read my full </strong></em><a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review" data-dimension112="7c4ce2e6-cc16-49eb-b3bc-47ad5b9134d5" data-action="Deal Block" data-label="E" data-dimension48="E" data-dimension25="$129"><em><strong>E</strong></em></a><a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review"><em><strong>difier ES60 review</strong></em></a><em><strong>.</strong></em><a class="view-deal button" href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow" data-dimension112="7c4ce2e6-cc16-49eb-b3bc-47ad5b9134d5" data-action="Deal Block" data-label="E" data-dimension48="E" data-dimension25="$129">View Deal</a></p></div><h2 id="the-can-withstand-anything-party-speaker">The 'can-withstand-anything' party speaker</h2><div class="product"><a data-dimension112="8a5aa552-93af-4dc6-97e9-d84404893cd8" data-action="Deal Block" data-label="Marshall Bromley 750 review" data-dimension48="Marshall Bromley 750 review" data-dimension25="$1299" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1294px;"><p class="vanilla-image-block" style="padding-top:115.92%;"><img id="5VnWQZR5GSzbp9Xz2zLhd9" name="bromley-750-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/5VnWQZR5GSzbp9Xz2zLhd9.jpg" mos="" align="middle" fullscreen="" width="1294" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Bromley 750 is Marshall’s debut party speaker, and it’s a triumph. Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. While not exactly small, it's IP54 waterproof and features a drainage system to get rid of any water that manages to get in.</p><p><em><strong>Read my full </strong></em><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review" data-dimension112="8a5aa552-93af-4dc6-97e9-d84404893cd8" data-action="Deal Block" data-label="Marshall Bromley 750 review" data-dimension48="Marshall Bromley 750 review" data-dimension25="$1299"><em><strong>Marshall Bromley 750 review</strong></em></a><em><strong>.</strong></em><a class="view-deal button" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow" data-dimension112="8a5aa552-93af-4dc6-97e9-d84404893cd8" data-action="Deal Block" data-label="Marshall Bromley 750 review" data-dimension48="Marshall Bromley 750 review" data-dimension25="$1299">View Deal</a></p></div><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-O95a2O"></div>                            </div>                            <script src="https://kwizly.com/embed/O95a2O.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/the-only-bluetooth-speaker-you-need-for-pool-parties-costs-less-than-usd40-no-im-not-joking">The only Bluetooth speaker you need for pool parties costs less than $40 — no, I’m not joking</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/as-a-guitarist-and-an-audiophile-this-is-the-all-in-one-speaker-ive-been-waiting-for">As a guitarist and an audiophile, this is the all-in-one speaker I’ve been waiting for</a></li><li><a href="https://www.tomsguide.com/audio/speakers/edifier-qr65-premium-speakers-from-a-traditionally-budget-brand">‘I didn’t think a traditionally budget brand could make such good premium speakers’ — here’s why the Edifier QR65 are never leaving my desk</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested the Audio Pro Addon C5 MKII, and it's a stylish, buildable home hi-fi system — but a few things hold it back ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/audio-pro-addon-c5-mkii-review</link>
                                                                            <description>
                            <![CDATA[ I’ve been testing the Audio Pro Addon C5 MKII, a retro-looking speaker with Wi-Fi streaming capabilities for great sound. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">xFRy4Upz9WDhZCRM7ZUCgF</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/9NstBhN7AUMwZ62g49TetQ-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 13 Feb 2026 15:29:01 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:31 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/9NstBhN7AUMwZ62g49TetQ-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background]]></media:description>                                                            <media:text><![CDATA[Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/9NstBhN7AUMwZ62g49TetQ-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Audio Pro Addon C5 MKII is a visually stunning speaker. It’s perfect for anyone looking to upgrade the aesthetics of their home interior with a good-looking sound system. Wi-Fi audio streaming and stereo capabilities also make this speaker a great choice for multi-room audio in a home audio setup.</p><p>The controls are easy to use, offering everything you could need at the touch of a button, but be mindful that this speaker needs to be plugged in to have power, so it can’t be moved around with you. </p><p>EQ control is limited, while sound quality also suffers at higher volumes. So could this be the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-these-are-the-best-ones-ive-used-in-2025">best Bluetooth speaker</a> to upgrade your home listening? Keep reading this full Audio Pro Addon C5 MKII review to find out. </p><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-specs"><span>Audio Pro Addon C5 MKII review: Specs </span></h3><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Audio-Pro-C5-Bluetooth-Multiroom/dp/B09NM4HRDK" target="_blank" rel="nofollow">$219</a>/<a href="https://uk.audiopro.com/products/addon-c5-mkii-multi-room-speaker" target="_blank" rel="nofollow">£260</a></p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>9.8 x 5.9 x 5.1 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>5.5 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, Grey, White</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Wi-Fi 2.4GHz, Wi-Fi 5 GHz, AirPlay2, Google Cast, Bluetooth, RCA</p></td></tr><tr><td class="firstcol " ><p><strong>Power</strong></p></td><td  ><p>Corded electric</p></td></tr><tr><td class="firstcol " ><p><strong>App</strong></p></td><td  ><p>Yes</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-price-availability"><span>Audio Pro Addon C5 MKII review: Price & availability</span></h3><p>The Audio Pro Addon C5 MKII is available at <a href="https://www.amazon.com/Audio-Pro-C5-Bluetooth-Multiroom/dp/B09NM4HRDK" target="_blank" rel="nofollow">Amazon U.S. for $219</a>, and at <a href="https://uk.audiopro.com/products/addon-c5-mkii-multi-room-speaker" target="_blank" rel="nofollow">Amazon U.K. for £260</a>. The speaker comes in a variety of colors, including White, Black and Grey. I tested the white colorway, and it fit in perfectly with my at-home audio setup. </p><p>This price point puts the speaker in the middle of the road for plug-in home speakers. The C5 MKII even comes with Wi-Fi streaming options, which gives it a leg up over the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/klipsch-the-one-plus-review">Klipsch The One Plus</a> that costs $274. But if you’re not looking for a plug-in speaker but still want something to fill your home with sound and look good while doing it, the <a href="https://www.tomsguide.com/audio/bose-soundlink-home-review">Bose SoundLink Home</a> ($219) offers deep bass performance. </p><p>If you want stereo sound, though, remember you’ll need to buy two C5 MKIIs (I was sent two to test the stereo linking). For stereo sound out of the box, bookshelf speakers like the <a href="https://www.tomsguide.com/audio/speakers/edifier-m60-review">Edifier M60</a> have the same retro look and offer stereo audio for $199. Or for a more compact offering, you could take a look at the <a href="https://www.tomsguide.com/audio/kanto-ora4-review">Kanto Ora4</a> speakers ($399), which deliver studio sound for a more professional setup but don’t offer multi-room connectivity or Wi-Fi streaming.</p><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-design-controls"><span>Audio Pro Addon C5 MKII review: Design & controls</span></h3><ul><li><strong>Good-looking</strong></li><li><strong>Angled for better sound</strong></li><li><strong>Easy to use controls</strong></li></ul><p>You shouldn’t trust anyone who tells you the C5 MK II is ugly. They’re lying. How do I know this? Because retro is in, baby, and anyone who knows anything about the zeitgeist will tell you the same. The Audio Pro Addon C5 MKII’s retro look and exposed central driver are incredibly sleek. I’ve got the White version here, which looks totally polished. </p><p>The handle on top might suggest this is a “luggable” speaker, but the power port in the back and the need for it to be permanently plugged in would wake you from your hopeful stupor. So once you find its home, it won’t be moving; not that you’d want to, given that it looks so good. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="h4SK4p3T8WGmtHvdci3sCR" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/h4SK4p3T8WGmtHvdci3sCR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Addon C5 MKII measures 9.8 x 5.9 x 5.1 inches and is just a bit smaller than the Klipsch The One Plus speaker, which measures 12.5 x  6.1 x 6.0 inches. I set it up on my cabinet next to my turn table, and it fit in perfectly. It only weighs 5.5 pounds and is very light to lift if needed, but since it’s a wired speaker, you won’t be doing much walking around with it. </p><p>For a larger speaker on the portable side, you should look to the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit Stormbox Lava</a> ($129), which weighs about the same as the C5 MKII at 5.1 pounds. But since it has 24 hours of battery life, it’s a viable option for camping trips and picnics.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="AE8pENp7k8Sh6XiUyX9C7R" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/AE8pENp7k8Sh6XiUyX9C7R.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The speaker has two larger feet at the front to angle it upward. This is to create the optimal conditions for playback. Having the tweeters pointed upwards can reduce muffled audio and reduce any sound reflections that may be caused by whatever surface you have the speaker on. When I angled the speaker to be more level with the table it was on, the sound became more muffled, so the feet are a great addition here.  </p><p>The controls (which I’ll talk about below) sit on the top of the speaker at the front and have a brushed silver finish. There are lights here to let you know what input mode the speaker is using. This is easy to switch between using the buttons on top. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="jreFRdvzi9WCXrFaAydSvQ" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/jreFRdvzi9WCXrFaAydSvQ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The controls of the Audio Pro Addon C5 MKII are very easy to use. The buttons sit at the top of the speaker, and there are 13 in total, which may appear daunting at first glance, but they’re actually very straightforward to use. </p><p>The controls for power, connectivity, and playback can be found on the left-hand side. There’s a larger button in the middle for controlling volume, which offers alterations in small increments to get the perfect level for your listening.</p><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-connectivity"><span>Audio Pro Addon C5 MKII review: Connectivity</span></h3><ul><li><strong>Wi-Fi streaming</strong></li><li><strong>Bluetooth streaming</strong></li><li><strong>Built-in charger</strong></li></ul><p>The C5 MKII can be used in a multi-room speaker setup or in stereo using the app, which I will go into later. The speaker has both  Wi-Fi 2.4GHz and 5GHz, making it compatible with AirPlay2 and Google Cast. Wi-Fi- streaming can also provide superior sound when compared with Bluetooth, as there is less compression, and I noticed that the connection to my device was stronger when streaming. The Wi-Fi connection took a lot of trial and error to get going, but it eventually worked. The Bluetooth was a lot more straightforward to connect to, just like any other Bluetooth speaker.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WFDxf4ZZacYaLra6VpNEAR" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/WFDxf4ZZacYaLra6VpNEAR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The speaker can also be used with Bluetooth for quick and easy streaming. You also have the option to use RCA cables if you want to use the speaker as an output for a turntable.<strong> </strong>There’s also a USB output at the back of the speaker for charging devices. I simply plugged in my phone charger, and it juiced up my phone.</p><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-app"><span>Audio Pro Addon C5 MKII review: App</span></h3><ul><li><strong>Not enough EQ customization</strong></li><li><strong>Can configure controls in-app</strong></li><li><strong>Multi-room connectivity</strong></li></ul><p>The speaker has six preset buttons that are configurable via the app. In conjunction with the app, you can set commands for the numbered presets on top of the speaker. This gives you instant access to radio stations and playlists from compatible streaming services. The speakers can be used with Spotify Connect and Tidal Connect.</p><p>In the Audio Pro app, I was able to assign one speaker as the left and one speaker as the right. This made my music sound great.  The app also allows for customization of EQ settings, although this is limited to bass and treble alterations only. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="AZKdTwSYzpP4xZdYPxj5YM" name="Audio Pro app screenshots" alt="Audio Pro app screenshots" src="https://cdn.mos.cms.futurecdn.net/AZKdTwSYzpP4xZdYPxj5YM.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable"><a href='https://cdn.mos.cms.futurecdn.net/AZKdTwSYzpP4xZdYPxj5YM.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Audio Pro)</span></figcaption></figure><p>I also tried out the multi-room function, which was easy to control when using Wi-Fi streaming. The sound was pretty good as I walked through the house, and I could even control the volume of each individual speaker from the app, depending on where I was.</p><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-sound-quality"><span>Audio Pro Addon C5 MKII review: Sound quality</span></h3><ul><li><strong>Wi-Fi streaming sounds better</strong></li><li><strong>Stereo set-up</strong></li><li><strong>Struggles at louder volumes</strong></li></ul><p>I streamed my music over Wi-Fi via <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, our best music streaming service for audiophiles, to get the best possible sound. The Audio Pro Addon C5 MKII has great sound quality, but there are a few little quirks that stop me from being a real lover. </p><p>That said, the speaker isn’t inherently bad; it just depends on what you like listening to. I have a pretty eclectic taste, so I was challenging the speaker with everything from metal to country to drum and bass — maybe I just gave it whiplash. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rXDUWXiNiP2iv4kCTFvjtQ" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/rXDUWXiNiP2iv4kCTFvjtQ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>First up, I listened to <em>Half Mast</em> by Empire Of The Sun. This track admittedly has a lot going on, from driving drum beats to higher-pitched synth; there’s a lot to take in. At loud volumes, I immediately noticed that the track sounded plasticky and a little warped — it sounded like a basketball was bouncing on the kick drum hits and the bass points. Despite this, the vocals remained strong and prominent while the percussion also shone. Some of the higher synths were completely lost unless the treble was turned all the way up, which is a symptom of a low-quality tweeter. </p><p>Next, I played <em>You Get What You Give </em>by the New Radicals, which is driven by a drum beat and a roaring electric guitar. The falsetto vocals remained strong throughout the song, much like the higher piano on the track, but as I turned the volume up a little, only to around 50%, I started to run into some issues. The drums became muddy, and there was a lot of confusion happening between the frequencies. There was also some very slight static creeping in. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UQEE9jk4caaVB5t4FiEiGR" name="Audio Pro C5 MKII" alt="Audio Pro C5 MKII Bluetooth speaker in white photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/UQEE9jk4caaVB5t4FiEiGR.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Finally, I  listened to <em>Potion </em>by Djo, which is my favorite song at the moment, so I’ve had it on repeat. And boy was I happy that this speaker could cope with the melodic acoustic guitar and gentle vocals. This made it totally clear that this track thrives in conditions with softer music, so maybe stay away from the hard stuff with it. That said, it sounded better with the bass lowered (which is something I never think) and the treble brought a little higher. The speaker certainly suits more purposeful sounds like acoustic fingerpicking without too much going on in the background. </p><p>While I didn’t always love the sound when using one speaker, when using two of the speakers in stereo, it’s hard to complain too much. The sound is a lot fuller, and since elements of the song are spaced out between the two speakers, it sounds less muddled. Multi-room also sounds great and means I can fill my house with music. </p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/56999932?zone=GB-en"></iframe><h3 class="article-body__section" id="section-audio-pro-addon-c5-mkii-review-verdict"><span>Audio Pro Addon C5 MKII review: Verdict</span></h3><p>The Audio Pro Addon C5 MKII is a stylish speaker that’s perfect for anyone looking to step into the world of plug-in home speakers. It’s totally versatile, with Wi-Fi, Bluetooth, and plug-in streaming options, and even has multi-room capabilities. Stereo set-up is also a win here, as being able to split two speakers between right and left made the music sound so much better. </p><p>There are some letdowns, though, including the sound quality suffering at higher volumes, and very limited EQ customization options. But the speaker performs well with softer acoustic music. It really depends on what type of music you listen to. If you’re into metal and rock, this might be one to avoid, but acoustic pop and indie will complement the speaker well. </p><p>All in all, it’s a decent speaker, and when paired with another, they can create pretty decent sound. </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living — here are my 5 favorite deals for Presidents' Day ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-here-are-my-5-favorite-deals-for-presidents-day</link>
                                                                            <description>
                            <![CDATA[ I test audio gear for a living, and these are the Bluetooth speakers I would spend my money on. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">VSHG5sszutvxMpSxTZZdS9</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/nKgLaXwrZFj2H8MgvASwNG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 13 Feb 2026 11:34:45 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money.She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK online, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews.She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health, and has her own newsletter where she shares reviews of her favorite books, Ashley’s Reading Nook. In previously published work, she has reviewed live music events, books, and wellness products.She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best.In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest fantasy novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/nKgLaXwrZFj2H8MgvASwNG-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:description>                                                            <media:text><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/nKgLaXwrZFj2H8MgvASwNG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>After a whole year of testing audio gear, I’ve listened to my fair share of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>, from expensive flagship models to budget-friendly boomers. And one thing I’ve learned is that the price you pay doesn’t necessarily dictate how good the sound quality is going to be, and the prices are better than ever this President's Day weekend. </p><p>While I’ve listened to some speakers that made me truly hate music (for about ten minutes), these are the ones that I would spend my money on. These span from audiophile winners to rugged speakers perfect for the outdoors. My favorite under $30 is the <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow">Tribit PocketGo Speaker for $19 at Amazon</a>. It's my go-to speaker for everything from outdoor adventures to my shower playlist.</p><p>Likewise, the <a href="https://www.amazon.com/Edifier-Bluetooth-Waterproof-Dustproof-Connectivity/dp/B0DTHMKKGR" target="_blank" rel="nofollow">Edifier ES20 Speaker for $76 at Amazon</a> is a solid pick. (Make sure to click the digital on-page coupon to get this price). Despite its small size, it give off huge sound and it can even be paired if you have multiple speakers.</p><p>I’m a firm believer that everyone should have a good quality speaker to take on the elements as well as a great at-home speaker. These portable speakers are ideal for at home or out and about, and pack a total punch in the sound department. (For more deals, check out our guide to the best <a href="https://www.tomsguide.com/sales-events/presidents-day-sales-2026-all-the-best-deals-id-buy">Presidents' Day sales</a>).</p><ul><li><strong></strong><a href="https://www.amazon.com/bluetooth-speakers-sale/s?k=bluetooth+speakers+on+sale" target="_blank" rel="nofollow"><strong>shop all Bluetooth speakers on sale at Amazon</strong></a><strong></strong></li></ul><h2 id="best-under-30-tribit-pocketgo">Best Under $30: Tribit PocketGo</h2><div class="product"><a data-dimension112="b27bf6bc-ffd3-4d2b-ad41-da295d283d1b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="XnqELzjemVWDKqXxoESeBh" name="tribit-pocketgo-bluetooth-shower-speaker-e7119067-af9e-4c09-9feb-6f1f593c89d6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XnqELzjemVWDKqXxoESeBh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review" data-dimension112="b27bf6bc-ffd3-4d2b-ad41-da295d283d1b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19">Tribit PocketGo</a> will be your new best friend. For less than $30, this Bluetooth speaker packs one heck of a punch in the sound department, and with some very minor EQ adjustments in the Tribit app, it quickly became my go-to speaker for everything from outdoor adventures to my shower playlist. </p><p>On top of that, it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for long hikes in unpredictable weather. And I do mean <em>long</em> hikes because the speaker has a total battery life of 20 hours, making it ideal for a weekend camping trip. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="b27bf6bc-ffd3-4d2b-ad41-da295d283d1b" data-action="Deal Block" data-label="Tribit PocketGo" data-dimension48="Tribit PocketGo" data-dimension25="$19">View Deal</a></p></div><h2 id="retro-chic-marshall-acton-iii">Retro Chic: Marshall Acton III</h2><div class="product"><a data-dimension112="a5353429-312b-42ea-834f-f064d92a4553" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market. And with $100 off for Presidents' Day, this is a total steal right now. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton. The bass is also super responsive, making it a top-tier choice for parties." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market. And with $100 off for Presidents' Day, this is a total steal right now. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton. The bass is also super responsive, making it a top-tier choice for parties." data-dimension25="$199" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Cream/dp/B0BBYF2SXX" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="VK72LAYkKKEKEWGPQxGoBn" name="marshall-acton-iii-bluetooth-home-speake-9c29b8fe-0398-481f-b43e-eb4a003dadde.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VK72LAYkKKEKEWGPQxGoBn.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. </p><p>It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market. And with $100 off for Presidents' Day, this is a total steal right now. </p><p>Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton. The bass is also super responsive, making it a top-tier choice for parties.<a class="view-deal button" href="https://www.amazon.com/Marshall-Acton-Bluetooth-Speaker-Cream/dp/B0BBYF2SXX" target="_blank" rel="nofollow" data-dimension112="a5353429-312b-42ea-834f-f064d92a4553" data-action="Deal Block" data-label="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market. And with $100 off for Presidents' Day, this is a total steal right now. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton. The bass is also super responsive, making it a top-tier choice for parties." data-dimension48="The Marshall Acton III is a retro-looking Bluetooth speaker that's can actually make your setup feel more modern. The physical controls and tactile and satisfying, making sure it's easy for you to get the sound you want. It needs to be plugged into the wall to work, but that doesn't stop it from producing some of the best sound on the market. And with $100 off for Presidents' Day, this is a total steal right now. Thanks to its large cabinet size and quality audio engineering inside, it's hard to be disappointed in the Acton. The bass is also super responsive, making it a top-tier choice for parties." data-dimension25="$199">View Deal</a></p></div><h2 id="best-all-around-jbl-flip-7">Best All Around: JBL Flip 7</h2><div class="product"><a data-dimension112="5e7b374a-34f5-4137-887c-ce5c710e988e" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$149" href="https://www.amazon.com/JBL-Bluetooth-Waterproof-Dustproof-Drop-Proof/dp/B0F72SMNWL" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="rdtu95ii9RqLZ9nbfKAwQT" name="jbl-flip-7-portable-bluetooth-speaker-ip-ff6d8340-c5af-4d18-b065-1355e1737605.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/rdtu95ii9RqLZ9nbfKAwQT.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Flip series from JBL has long been a favorite of mine. They always seem to nail the sound while keeping the size suitably portable. And the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet" data-dimension112="5e7b374a-34f5-4137-887c-ce5c710e988e" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$149">JBL Flip 7</a> is no exception to that rule. You can also choose from seven colors, so this speaker becomes a real statement. </p><p>This speaker can last you up to 16 hours between charges, so this compact speaker packs a lot of juice. But the sound quality will win you over here. The vocals and trebles are detailed and clean, while the bass offers plenty of that famous JBL oomph. </p><p>It’s also pretty rugged, with the ability to survive against sand, dirt and water.<a class="view-deal button" href="https://www.amazon.com/JBL-Bluetooth-Waterproof-Dustproof-Drop-Proof/dp/B0F72SMNWL" target="_blank" rel="nofollow" data-dimension112="5e7b374a-34f5-4137-887c-ce5c710e988e" data-action="Deal Block" data-label="JBL Flip 7" data-dimension48="JBL Flip 7" data-dimension25="$149">View Deal</a></p></div><h2 id="best-for-hiking-jbl-go-4">Best for hiking: JBL Go 4</h2><div class="product"><a data-dimension112="3f4e3b0b-7c42-4996-928b-81de4d6f058b" data-action="Deal Block" data-label="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound.It's small enough to take traveling, and will asily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension48="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound.It's small enough to take traveling, and will asily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension25="$39" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNWBT1Z" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="uQJgL3k2xaEEAQXb6mspWh" name="jbl-go-4--ultraportable-waterproof-and-d-327de61a-f398-40ce-b539-115ea309ca87.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/uQJgL3k2xaEEAQXb6mspWh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound.</p><p>It's small enough to take traveling, and will asily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. </p><p>It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties.<a class="view-deal button" href="https://www.amazon.com/JBL-Ultra-Portable-Waterproof-Dustproof-Built/dp/B0CTNWBT1Z" target="_blank" rel="nofollow" data-dimension112="3f4e3b0b-7c42-4996-928b-81de4d6f058b" data-action="Deal Block" data-label="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound.It's small enough to take traveling, and will asily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension48="The JBL Go 4 is a decent portable Bluetooth speaker for anyone on a budget that still wants decent levels of sound.It's small enough to take traveling, and will asily clip on the outside of your bag to soundtrack hikes. The IP67 water and dust protection rating, mean it can also withstand pretty much any weather condition thrown at it. It can also provide decent sound for small gatherings, and multi-point connectivity means you can share soundtracking duties." data-dimension25="$39">View Deal</a></p></div><h2 id="bonkers-battery-life-marshall-kilburn-iii">Bonkers Battery Life: Marshall Kilburn III</h2><div class="product"><a data-dimension112="2ddf06f3-bf17-4fdd-bb4e-a864d9e6a701" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349" href="https://www.amazon.com/Marshall-Kilburn-Portable-Bluetooth-Speaker/dp/B0F96FWCDF" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="EnMyj8ixQyTihJkRabigMZ" name="marshall-kilburn-iii-portable-bluetooth--ce671c25-c944-4392-ac82-2fa44f696a5b.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/EnMyj8ixQyTihJkRabigMZ.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review" data-dimension112="2ddf06f3-bf17-4fdd-bb4e-a864d9e6a701" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">Marshall Kilburn III</a> isn’t just a pretty face — it’s a powerhouse of sound quality. The battery life is totally impressive, and the on-device time controls make keeping the music going easier than anything else. </p><p>This is one of the best-looking speakers out there, but that’s no surprise given that this is a Marshall speaker. But what really wins me over? The epic 50-hour battery life. This speaker can literally last me weeks without needing to charge it up. </p><p>It produces sound with epic bass, perfect for listening to the likes of Charli XCX, and that makes it something of a party monster. You’re never going to be let down by the sound here. <a class="view-deal button" href="https://www.amazon.com/Marshall-Kilburn-Portable-Bluetooth-Speaker/dp/B0F96FWCDF" target="_blank" rel="nofollow" data-dimension112="2ddf06f3-bf17-4fdd-bb4e-a864d9e6a701" data-action="Deal Block" data-label="Marshall Kilburn III" data-dimension48="Marshall Kilburn III" data-dimension25="$349">View Deal</a></p></div><h2 id="shop-all-presidents-day-deals">Shop all Presidents' Day deals</h2><ul><li><a href="https://www.amazon.com/deals" target="_blank" rel="nofollow"><strong>shop Presidents' Day at Amazon</strong></a><strong></strong></li><li><strong>Disney+ Hulu bundle: </strong><a href="https://www.disneyplus.com/" target="_blank" rel="nofollow"><strong>was $12/mo now $9/mo</strong></a></li><li><strong>Carhartt:</strong><a href="https://www.amazon.com/stores/page/4D749FEE-ACA7-4043-8DF6-FCA7CF7BEE1F/deals" target="_blank" rel="nofollow"><strong> deals from $6 @ Amazon</strong></a></li><li><strong>Lululemon: </strong><a href="https://shop.lululemon.com/c/women-we-made-too-much/n16o10z8mhd" target="_blank" rel="nofollow"><strong>from $7 @ Lululemon</strong></a></li><li><strong>The North Face: </strong><a href="https://www.thenorthface.com/en-us/sale-c829803" target="_blank" rel="nofollow"><strong>apparel from $13</strong></a><strong></strong></li><li><strong>Amazon devices: </strong><a href="https://www.amazon.com/events/devicedeals" target="_blank" rel="nofollow"><strong>Ring, Blink, Fire TVs from $17</strong></a></li><li><strong>Shark/Ninja appliances: </strong><a href="https://www.walmart.com/shop/shark-ninja-home-savings-event?facet=brand%3ANinja&povid=D14_ShopAllNinjaMerchModule_SharkNinjaFY25JulyEvent" target="_blank" rel="nofollow"><strong>deals from $59 @ Walmart</strong></a></li><li><strong>TV sale: </strong><a href="https://www.amazon.com/tvs/b?ie=UTF8&node=172659" target="_blank" rel="nofollow"><strong>deals from $59 @ Amazon</strong></a><strong></strong></li><li><strong>IKEA winter sale: </strong><a href="https://www.ikea.com/us/en/offers/limited-time-offers/" target="_blank" rel="nofollow"><strong>up to 50% off </strong></a></li><li><strong>Saatva luxury beds: </strong><a href="https://www.saatva.com/mattresses/saatva-classic" target="_blank" rel="nofollow"><strong>from $999 @ Saatva</strong></a></li></ul><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review">This budget speaker looks totally premium — and it almost nails it in the sound department too</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-jbuds-party-review">JLab JBuds Party review: A meatier portable speaker, but at what cost?</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/expensive-doesnt-mean-good-heres-why-ill-be-sticking-with-my-usd40-speaker-over-this-usd200-one">'Expensive doesn’t mean good’: here’s why I’ll be sticking with my $40 speaker over this $200 one</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I tested this Bluetooth speaker with 20 hours of battery life, and it's only $19 for Presidents' Day deals ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-tested-this-bluetooth-speaker-with-20-hours-of-battery-life-and-only-costs-usd19-in-the-presidents-day-deals</link>
                                                                            <description>
                            <![CDATA[ The Tribit PocketGo Bluetooth speaker is my go-to for any adventure, and it's currently at its lowest ever price. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">q67E5qMh9yRH2jYxmVf2NP</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/4CMRVqBfwxyLMbPSReRNTW-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 12 Feb 2026 12:13:26 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money.She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK online, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews.She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health, and has her own newsletter where she shares reviews of her favorite books, Ashley’s Reading Nook. In previously published work, she has reviewed live music events, books, and wellness products.She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best.In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest fantasy novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/4CMRVqBfwxyLMbPSReRNTW-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Tribit PocketGo Bluetooth Speaker photographed in front of a blue background with a Presidents&#039; Day deals badge]]></media:description>                                                            <media:text><![CDATA[Tribit PocketGo Bluetooth Speaker photographed in front of a blue background with a Presidents&#039; Day deals badge]]></media:text>
                                <media:title type="plain"><![CDATA[Tribit PocketGo Bluetooth Speaker photographed in front of a blue background with a Presidents&#039; Day deals badge]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/4CMRVqBfwxyLMbPSReRNTW-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've tested my fair share of speakers here at Tom's Guide, and one feature that always sticks out to me is the battery life. I need to make sure I have enough juice to take the speaker with me on walks, or day trips to the beach. </p><p>I also need to know the speaker can withstand everything thrown at it come rain or shine. That's Where the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a> comes in. It's an uber affordable speaker that can take on water, dust, or falls with ease. And right now for Presidents' Day sales, the speaker has dropped to its lowest price. You pick up the <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow">Tribit PocketGo at Amazon for just $19</a>. </p><div class="product"><a data-dimension112="13d4640d-70cd-4d7b-ac8b-0eaa5c2d6608" data-action="Deal Block" data-label="The Tribit PocketGo has hit it's lowest price in the Presidents' Day deals at Amazon. It's a rugged speaker with an IP68 waterproof rating, making it ideal for adventures along with military grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="The Tribit PocketGo has hit it's lowest price in the Presidents' Day deals at Amazon. It's a rugged speaker with an IP68 waterproof rating, making it ideal for adventures along with military grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$19" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:500px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="XnqELzjemVWDKqXxoESeBh" name="tribit-pocketgo-bluetooth-shower-speaker-e7119067-af9e-4c09-9feb-6f1f593c89d6.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/XnqELzjemVWDKqXxoESeBh.jpg" mos="" align="middle" fullscreen="" width="500" height="500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit PocketGo has hit it's lowest price in the Presidents' Day deals at Amazon. It's a rugged speaker with an IP68 waterproof rating, making it ideal for adventures along with military grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes. <a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Electronics/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="13d4640d-70cd-4d7b-ac8b-0eaa5c2d6608" data-action="Deal Block" data-label="The Tribit PocketGo has hit it's lowest price in the Presidents' Day deals at Amazon. It's a rugged speaker with an IP68 waterproof rating, making it ideal for adventures along with military grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension48="The Tribit PocketGo has hit it's lowest price in the Presidents' Day deals at Amazon. It's a rugged speaker with an IP68 waterproof rating, making it ideal for adventures along with military grade drop protection. After making some minor EQ adjustments in the Tribit app, the speaker sounds great and reaches super loud volumes." data-dimension25="$19">View Deal</a></p></div><h2 id="music-all-day-long">Music all day long</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ryja4TD89MLWDNspHawtiZ" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/ryja4TD89MLWDNspHawtiZ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>When I head out on a hike and take a speaker with me, I always worry about running out of battery halfway along the trail. This is extremely annoying as music is a huge source of motivation for me, but the PocketGo has taken away those worries. </p><p>With a whopping 20 hours of battery life, the Tribit PocketGo can support my listening all day long, even at higher volumes. I've previously taken it with me on a weekend trip and didn't need to charge it once even though I was listening to music all day every day.</p><h2 id="a-rugged-beauty">A rugged beauty</h2><p>It may not be the prettiest speaker, but the PocketGo offers military-grade levels of protection against the elements. With a waterproof and dustproof rating of IP68, the speaker is totally dust-tight, meaning you can take it to the beach and not worry about sand getting in everywhere, and you can even submerge it in up to 1.5 meters of water for 30 minutes. </p><p>The PocketGo has even come in the shower with me to totally elevate my karaoke (sorry to my neighbors). But if you love taking a speaker to add a soundtrack to your hikes, and are a butter fingers like myself, you'll appreciate the drop protection.</p><p>The PocketGo has a durability rating of MIL-STD-810H, which in layman's terms means that it can survive a four-foot drop. I never need to worry about this speaker, even when it's clipped to the outside of my bag in the rain. </p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review"><strong>Tribit PocketGo review</strong></a></li><li><a href="https://www.tomsguide.com/entertainment/streaming/15-years-later-crazy-stupid-love-has-a-chaotic-twist-that-makes-it-one-of-the-very-best-rom-coms-stream-it-now-on-netflix"><strong>15 years later, 'Crazy, Stupid, Love' has a chaotic twist that makes it one of the very best rom-coms — stream it now on Netflix</strong></a></li><li><a href="https://www.tomsguide.com/phones/iphones/my-iphone-now-helps-me-get-a-good-nights-sleep-heres-how-this-hidden-ios-feature-can-help-you-too"><strong>My iPhone now helps me get a good night’s sleep — here’s how this hidden iOS feature can help you too</strong></a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ This budget speaker looks totally premium — and it almost nails it in the sound department too ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es20-review</link>
                                                                            <description>
                            <![CDATA[ The Edifier ES20 offers huge sound for under $100, but a lack of EQ control and static has me questioning if it’s worth it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">jHcfTKjXYZnqQPR5uJGyeH</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/JjUsKaw7wyzvSn6E6MeDdG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 06 Feb 2026 12:31:39 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:28 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/JjUsKaw7wyzvSn6E6MeDdG-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:description>                                                            <media:text><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/JjUsKaw7wyzvSn6E6MeDdG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The Edifier ES20 is an incredibly sleek-looking Bluetooth speaker with a premium build that can get very loud, but is it one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a>? Well, I don’t think so, but it’s not inherently bad either. </p><p>It’s compact and great for outdoors, and even has a stereo pairing option. But as someone who listens to a lot of rock and punk music, I was let down by the static on heavy tracks, which caused some clipping. There’s also no control in the app to alter the EQ to fix this. </p><p>If you’re in the U.S., you’re also going to be paying nearly double the U.K.  price — but it’s still under $100. So, you can find out if this is the right speaker for you by reading this full Edifier ES20 review.</p><h3 class="article-body__section" id="section-edifier-es20-review-specs"><span>Edifier ES20 review: Specs</span></h3><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://edifier-online.com/products/es20-portable-bluetooth-speaker" target="_blank" rel="nofollow">$89</a>/<a href="https://www.amazon.co.uk/Edifier-ES20-Bluetooth-Waterproof-Dustproof/dp/B0F8J2GMP7" target="_blank" rel="nofollow">£49</a></p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>3.7 x 3.6 x 2.0 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>11.5 ounces</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>12 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Lighting</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth V5.4</p></td></tr><tr><td class="firstcol " ><p><strong>Codec support</strong></p></td><td  ><p>SBC</p></td></tr><tr><td class="firstcol " ><p><strong>Dustproof and waterproof</strong></p></td><td  ><p>IP67</p></td></tr></tbody></table></div><h3 class="article-body__section" id="section-edifier-es20-review-price-availability"><span>Edifier ES20 review: Price & availability</span></h3><p>The Edifier ES20 is an uber cheap small speaker… if you’re in the U.K.. The pricing in the U.K. makes this speaker pretty affordable for <a href="https://www.amazon.co.uk/Edifier-ES20-Bluetooth-Waterproof-Dustproof/dp/B0F8J2GMP7" target="_blank" rel="nofollow">£49 at Amazon U.K.</a>, but when you head to the American point of purchase, the price increases to <a href="https://edifier-online.com/products/es20-portable-bluetooth-speaker" target="_blank" rel="nofollow">$89 on the Edifier USA online store</a>. And while I certainly recommend this speaker at the price point in the U.K., it’s quite the jump to the U.S. pricing. Although we can’t say for certain why there’s such a price discrepancy, last year, <a href="https://www.tomsguide.com/audio/earbuds/i-tested-these-would-be-airpods-contenders-with-magnetic-planar-drivers-but-the-tariffs-just-wrecked-my-rating">Edifier confirmed to my colleague Erin that it was forced to increase prices due to tariffs</a>. </p><p>So, if you want and even more budget-friendly speaker, let me point you in the direction of the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a> ($34/£29). Now, <em>that</em> is a speaker giving you value for money. It’s no secret that it’s one of my favorite speakers; however, the ES20 has an awesomely loud sound that packs a punch in the bass department. If bass is something you care about, it might be worth the extra investment.</p><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-wonderboom-4-review">Ultimate Ears Wonderboom 4</a> ($89) is our pick for <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html#section-best-bluetooth-speaker-for-outdoors">best Bluetooth speaker for outdoors</a> and has the same larger-than-life sound but offers a more rugged-looking design. But personally, I’d stick with the ES20 since I love the sleek look.</p><h3 class="article-body__section" id="section-edifier-es20-review-design-controls"><span>Edifier ES20 review: Design & controls</span></h3><ul><li><strong>Sleek and good-looking</strong></li><li><strong>IP67</strong></li><li><strong>LED lighting at the back</strong></li></ul><p>The Edifier ES20 looks far more premium than its price tag would suggest. The speaker is available in an Ivory color, which I tested, that comes with champagne metal accents to complement the faux ivory leather finish. The ES20 is also available in black with black and champagne metal accents. Both versions of the speaker look great, and a lot like the <a href="https://www.tomsguide.com/audio/marshall-willen-ii-review-rugged-rockin-fun">Marshall Willen II</a> ($99).</p><p>As I mentioned, the speaker is small enough to hold in the palm of my hand. It measures just 3.7 x 3.6 x 2.0 inches. Despite its compact size, it’s markedly heavier than other speakers in its size class. At 11.5 ounces, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-pop-party-review#section-jlab-pop-party-review-price-availability">JLab Pop Party</a>’s ($24) 8.7-ounce weight takes the crown for portability here.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="sVLerSfHyqgZUUfV6UnvdG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/sVLerSfHyqgZUUfV6UnvdG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>But that doesn’t mean it’s hard to take with you anywhere you go, since much like the Tribit PocketGo and the JLab Pop Party, there is a handy strap that can be secured to the outside of your bag. </p><p>If you want something with the same cool style that’s a little bigger, Edifier also makes the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review">ES60</a> ($199), which would be a better option for a speaker with meaty bass, but the lower battery life is a bit of a turn-off.</p><p>If you were planning on taking the ES20 with you on adventures, then its IP rating will please you. It has a dustproof and waterproof rating of IP67, meaning it can actually be submerged in water, even though it doesn’t look like a rugged speaker. In fact, it looks pretty premium. It resembles the look of one of my Fender guitar amps, which I really like, and even looks pretty similar to the Marshall Willen II (cough cough). It makes the ES20 speaker feel more like music equipment to be taken seriously rather than just another plasticky speaker. Until you turn it around, then it’s a whole different story.  </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="DxZnwmAiXzHesMUpbUzNiG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/DxZnwmAiXzHesMUpbUzNiG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>That brings me to the feature I don’t really use on the speaker because, frankly, I don’t quite understand its purpose: LED lighting. I feel this way about most Bluetooth speakers that come with this feature, but more so with the ES20 because, well, you can’t see it. The LED lighting that surrounds the edges of the speaker is at the back, where I typically wouldn’t be looking. And unless you have the speaker reflecting against the wall so it can reflect the light, it’s pretty much pointless and drains the battery. To me, they cheapen the otherwise premium feeling (and looking) design.</p><p>There are buttons at the top of the speaker to control the volume and lighting. As I mentioned, the lighting controls aren’t something I used much, but the volume controls mean I don’t need to reach for my phone when I need to turn down the noise. Five lights beneath the buttons depict how much charge is left in the speaker.</p><h3 class="article-body__section" id="section-edifier-es20-review-connectivity-app"><span>Edifier ES20 review: Connectivity & app</span></h3><ul><li><strong>Not much control in the app</strong></li><li><strong>SBC audio codec only</strong></li><li><strong>Stereo pairing available</strong></li></ul><p>There is a notable lack of Hi-Res compatibility with the Edifier ES20, as it can only play in the SBC audio codec. I usually stream in AAC from my iPhone, and while it won't be glaringly obvious to everyone, I noticed some static in heavier genres. But this is a budget speaker, so some sacrifices will be made to keep costs down, especially given the premium build.</p><p>The speaker is very loud on its own, but if you want it even louder, it also offers stereo pairing. So if you purchase two speakers, you can create a stereo-like sound. It also offers a multipoint connection for simpler streaming across devices. I was able to stream music from my laptop and easily switch over to listen to the audiobook on my phone. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nKgLaXwrZFj2H8MgvASwNG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/nKgLaXwrZFj2H8MgvASwNG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>You can also use the Edifier ConneX app with the speaker, but I was pretty disappointed by it. There is a severe lack of control with the app, as you don’t get many customization options to have a say in how you listen. Other brands like Tribit and JLab allow you to make custom EQ adjustments, and I think this would have vastly improved my listening experience with the ES20.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="x3hJxZWUaKiP4kHaN9BY7K" name="Edifier ES20" alt="Screenshots take using the Edifier Connex app showing the settings for the Edifier ES20" src="https://cdn.mos.cms.futurecdn.net/x3hJxZWUaKiP4kHaN9BY7K.jpg" mos="" align="middle" fullscreen="" width="1510" height="850" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Edifier)</span></figcaption></figure><p>The app does, however, give four sound effects: Music, Game, Movie and Outdoor. But they all sound the same. The only difference I noticed was that Movie used more bass performance to make the noise sound more rounded.</p><h3 class="article-body__section" id="section-edifier-es20-review-sound-quality"><span>Edifier ES20 review: Sound quality</span></h3><ul><li><strong>Vocals are strong</strong></li><li><strong>Issues with static on heavy tracks</strong></li><li><strong>Gets very loud</strong></li></ul><p>For under $100, the Edifier ES20 provides awesome sound in a super small package. I was actually shocked when I listened to it for the first time, because there’s no denying it, this thing gets <em>loud</em>. It actually rivalled the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit Stormbox Lava</a> ($129) — a much larger speaker — in volume. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hKXzdWbfyxAswY3SdqeAJG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/hKXzdWbfyxAswY3SdqeAJG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I listened to <em>Isn’t It Midnight</em> by Fleetwood Mac. This song features a lot of breathy vocals and guitar solos that present the mids and highs excellently. The speaker handled the vocals well, and nothing was lost in this heavily layered song. The guitar solos were super bright and remained prominent even when the vocals kicked back in. </p><p>I then moved on to <em>Alive</em> by Empire Of The Sun, a synth-heavy track. The speaker did a great job of balancing the vocals with the bass without the higher-pitched synth getting lost. But with that said, there was some masking when the percussion kicked in as they battled with the softer vocals.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SPphL9DefDfg94vgWfWq8G" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/SPphL9DefDfg94vgWfWq8G.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I played <em>Helena</em> by My Chemical Romance, and the guitar sounded pretty muddy. This song in particular sounded like it was being played over an old radio, which isn’t great. The static muddied the low end and made for a disappointing experience. Even so, the vocals remained strong, but I couldn’t get past the warped bass to enjoy the track.</p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/55100613?zone=GB-en"></iframe><h3 class="article-body__section" id="section-edifier-es20-review-battery-life"><span>Edifier ES20 review: Battery life</span></h3><ul><li><strong>12 hours of battery life</strong></li><li><strong>Lighting drains battery</strong></li><li><strong>Charges via USB-C</strong></li></ul><p>The Edifier ES20 charges via USB-C and offers 12 hours of battery life per charge. But be wary that if you’re using the lighting on the speaker, this will diminish a lot faster. That’s a lot more battery life than its larger counterpart, the Edifier ES60, which is only nine hours. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="B7tLiEgMWo8svWAfwtKaPG" name="Edifier ES20" alt="Edifier ES20 Bluetooth speaker in ivory colorway photographed on a blue background" src="https://cdn.mos.cms.futurecdn.net/B7tLiEgMWo8svWAfwtKaPG.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>However, the Tribit PocketGo offers a whopping 20 hours of battery life, so if you’re looking for something that can last you all day long for an outdoor adventure where you won’t have access to a charging point, that’s the way to go. Similarly, the Marshall Willen II, which is close in size to the ES20, offers 17 hours and would be more reliable for longer listening parties.</p><h3 class="article-body__section" id="section-edifier-es20-review-verdict"><span>Edifier ES20 review: Verdict</span></h3><p>The Edifier ES20 is a powerful speaker with style that delivers impressive volume and vocal clarity. It’s great for outdoor use since it can get incredibly loud and has a dustproof and waterproof rating of IP67. The speaker offers stereo pairing, so it's a great option for parties. </p><p>If you tend to listen to electronic or pop music, the speaker is a great choice, but if you lean toward heavier rock music, it might not be the right option. You can’t adjust EQ, even though other audio brands like JLab and Ultimate Ears offer custom EQ. The speaker is also a little more expensive in the U.S. than in the U.K.. Even so, it’s still under $100, but you might get better bang-for-buck elsewhere with the Tribit PocketGo. </p><p>With all that said, this is still a powerful speaker that packs a punch, and if you need a super compact that will look good anywhere, the ES20 is the way to go.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I just tested the JBL Flip 7 — is it the best compact Bluetooth speaker yet? ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-just-tested-the-jbl-flip-7-is-it-the-best-compact-bluetooth-speaker-yet</link>
                                                                            <description>
                            <![CDATA[ With its bulletproof design, thumping bass, and decent price point, the JBL Flip 7 is another outstanding Bluetooth speaker, with enough hardware and software smarts to justify an upgrade over the excellent Flip 6. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">PaW6wedgL4sCZNSNmqHsjH</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/7KkCcxtZ5HVEyE2hNQtayc-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 04 Feb 2026 08:15:00 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:18 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                                    <dc:creator><![CDATA[ Matt Ng ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/L9z5BTiYk2S23VYGqJGA5L.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/7KkCcxtZ5HVEyE2hNQtayc-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JBL Flip 7]]></media:description>                                                            <media:text><![CDATA[JBL Flip 7]]></media:text>
                                <media:title type="plain"><![CDATA[JBL Flip 7]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/7KkCcxtZ5HVEyE2hNQtayc-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <div  class="fancy-box"><div class="fancy_box-title">JBL Flip 7 review: Specs</div><div class="fancy_box_body"><p class="fancy-box__body-text"><strong>Price </strong>$149.95<br><strong>Colors </strong>Pink, blue, Red, Squad, Black, White, Purple<br><strong>Size</strong> 7.2 x 2.7 x 2.8 inches<br><strong>Weight </strong>‎1.82 pounds<br><strong>Battery life</strong> (rated) 14 hours<br><strong>Bluetooth version</strong> 5.4<br><strong>Connectivity</strong> Bluetooth, USB-C<br><strong>Durability</strong> Waterproof, dropproof & dustproof IP68</p></div></div><p>Wander into any tech shop, and scores of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> line whole aisles. They’re small, versatile, and often excellent value for money, and manufacturers face a cruel cycle of delivering innovation and sound quality while keeping prices down in this highly competitive audio segment.</p><p>I recently went hands-on with JBL’s mid-range Flip 7, successor to the Flip 6, and it has humongous shoes to fill. The Flip 6 was extremely well-received and struck an impressive balance with its portability and sonic performance.</p><p>So can the Flip 7 build on its success? Or is this one speaker that’ll be overshadowed by its Bose, Sonos, Ultimate Ears, and Marshall brethren?</p><h2 id="jbl-flip-7-review-price-availability">JBL Flip 7 review: Price & availability</h2><p>The Flip 7 is available from <a href="http://jbl.com"><u>JBL.com</u></a> for the reasonable sum of $149. It represents great value for money for such a compact speaker, perfect for those looking for a balance of great sound quality without wanting to drop $400 on a high-end model.</p><h2 id="jbl-flip-7-review-design-and-build">JBL Flip 7 review: design and build</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4000px;"><p class="vanilla-image-block" style="padding-top:56.30%;"><img id="wk6uQDmzuu3aQxuqwPFvvc" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/wk6uQDmzuu3aQxuqwPFvvc.jpg" mos="" align="middle" fullscreen="" width="4000" height="2252" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Flip 7 doesn’t stray too far from the form factor of JBL’s mainline Bluetooth speakers, like the Grip, Charge, and its predecessor, the Flip 6, with a tubular design and a slightly bulbous middle. It’s a more rugged, casual look, replete with the large and bold JBL logo on the front, so if you’re looking for something a little more elegant, you could go for something like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/sonos-roam-2-review">Sonos Roam 2</a>. </p><p>The large can-sized boomer is still designed to be grabbed single-handedly, though it’s heftier than it looks. Thankfully, there’s a new PushLock system with interchangeable accessories, including a fabric looped strap and carabiner, for more secure carrying. Still, it’s fine for slipping into the side pocket of a backpack.</p><p>The grill comprises thick, interwoven fabric with rubber bumpers at the edges. There’s also a small rubber backstop, so it’s less prone to rollover when placed down. </p><p>The speaker also comes in a choice of seven colors, including Red, Pink, Blue, Black, White, Purple, and the camouflaged Squad.</p><p>Everything from the weightiness, fabric grill, and the solid rubber bumpers oozes quality, so while the Flip 7 isn’t the most subtle speaker around, you know you’re getting a good product just from holding it.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SDZgmjbJgwxo4fKhUTw28c" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/SDZgmjbJgwxo4fKhUTw28c.png" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The speaker is absolutely ready to rough it up too, whether at the beach, the pool, or a bike trail. With its IP68 rating, it’s built to be protected against water and dust ingress, so it can shake off a tumble down a sand dune or fall into a hot tub and keep going.</p><p>New to the 7th-gen Flip is AI Sound Boost, which analyzes and optimizes speaker performance in real time, creating fuller audio at lower volumes and minimizing distortion when cranked up. </p><p>Another addition over the Flip 6 is lossless audio using a USB-C cable and a compatible platform, which is a boon for Spotify users enjoying its fairly new lossless service. Plus, its battery life has been tweaked up to 16 hours — 14 without the Playtime Boost option, which lessens the power draw from deeper bass notes.</p><p>Finally, JBL adds to its Auracast-compatible range with the Flip 7. This feature allows one device to broadcast to an unlimited number of other speakers without the standard Bluetooth pairing process.</p><h2 id="jbl-flip-7-review-controls-connectivity">JBL Flip 7 review: Controls & connectivity</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4000px;"><p class="vanilla-image-block" style="padding-top:56.30%;"><img id="BQK3tvx2TKndBGddje4eyc" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/BQK3tvx2TKndBGddje4eyc.jpg" mos="" align="middle" fullscreen="" width="4000" height="2252" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Controls-wise, we have the usual power, playback, and volume buttons. I also adore the separate Bluetooth button, super handy for those who second-guess the varying pairing hoops speakers make you jump through — “was it the power button or both volume buttons?” An Auracast button also makes its debut on the Flip series, letting you connect compatible speakers quickly and with no fuss.</p><p>Like its forebears, the Flip 7 still lacks skip buttons, with those features embedded within the play button itself — skip ahead with a double press, go to the previous with a triple press.</p><p>The JBL Portable smartphone app is also there to coordinate proceedings, letting you select preset equalizer settings or customize your levels, while the Playtime Boost option extends your listening time at the cost of your bass power. You can also hook in another Flip 7 for stereo listening, though sadly, alternate JBL speaker models won’t work for this function.</p><h2 id="jbl-flip-7-review-sound-quality">JBL Flip 7 review: Sound quality</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4000px;"><p class="vanilla-image-block" style="padding-top:56.30%;"><img id="FJL7mBUJbgbPdqpis6dnxc" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/FJL7mBUJbgbPdqpis6dnxc.jpg" mos="" align="middle" fullscreen="" width="4000" height="2252" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Sonically, the Flip 7 impressed me right from the outset. For a compact, mid-range boomer under $150, it performs like it was at least twice the price and twice the size. Thanks to its USB-C output, I was also able to test out non-compression playback via Spotify Lossless, which did not disappoint.</p><p>While so many sub-$100 speakers deliver reliably, with decent volume and bass, the Flip 7 rewrites the script on what’s possible with the portable variety. And while it’s easy to be skeptical of its AI SoundBoost feature, it does work. Even at low volumes, the bass rumble of The Prodigy’s Breathe pleasingly tickled my eardrums.</p><p>When you crank it up, every thud in Massive Attack’s Teardrop feels like a wallop to the ribcage, thanks to those visibly pulsing passive radiators and the woofer delivering that big sound that betrays the Flip 7’s smaller size. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:4275px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="eTRU5Au7d7gnaxxwXMFMAd" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/v2/t:3840,l:0,cw:4275,ch:2405,q:80/eTRU5Au7d7gnaxxwXMFMAd.jpg" mos="" align="middle" fullscreen="" width="4275" height="6412" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JBL)</span></figcaption></figure><p>Trebles and mids also feel detailed, complex, and well handled on the Flip 7. The haunting yet floaty notes of Alicia from the Clair Obscur: Expedition 33 soundtrack are rendered in crystal clear ethereal quality — at volume, I could really appreciate soprano Alice Duport-Percier’s emotional performance, clarity, and control. And that slinky yet eerie Latin percussion really cuts through in that first minute of Steely Dan’s Do It Again. In Michael Jackson’s Thriller, the complex and layered arrangement of synths, drums, guitars, and Vincent Price’s distinctive voiceover shines to great effect.</p><p>Only at the 85% volume does the bass start to buckle, but that level is honestly way more than you’d typically use (or find tolerable) in most settings. Speaking of bass, when plugged in with a USB-C for lossless playback, the speaker rested on my protruding cable instead of its rubber grip, and I’d find it spinning away on my desk when at high volume.</p><p>I was also itching to pair my JBL Grip with the Flip 7 to enable a proper stereo mode, but it’s a little disappointing that you need the exact model to unlock this feature. Still, I enjoyed using Auracast for wider coverage.</p><p>Naturally, the Flip 7’s smaller form factor has limitations — it won’t reproduce the lowest notes as there’s no subwoofer. It’s also still a mono speaker, so don’t expect much of a soundstage, though I’m seriously considering a second Flip for that stereo goodness.</p><p>As you might expect, this sadly isn’t the speaker for amping your laptop when streaming video or playing games. Its slower audio codecs mean voices and effects are delivered out of sync — not hugely, but noticeable enough to distract. Maybe we can have a low latency mode for the Flip 8? </p><h2 id="jbl-flip-7-review-battery-life">JBL Flip 7 review: Battery life</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:6001px;"><p class="vanilla-image-block" style="padding-top:56.26%;"><img id="heHjKDHa5tcYLANBqfGB9d" name="JBL Flip 7" alt="JBL Flip 7" src="https://cdn.mos.cms.futurecdn.net/v2/t:387,l:879,cw:6001,ch:3376,q:80/heHjKDHa5tcYLANBqfGB9d.jpg" mos="" align="middle" fullscreen="" width="7293" height="4864" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JBL)</span></figcaption></figure><p>The Flip 7 can go 14 hours (16 with Playtime Boost) between charges, which is respectable given its size and about accurate from my play testing. Still, it’s a middle of the pack stat for a Bluetooth speaker. Its bigger brother, the Charge 7, manages an impressive 24 hours of juice (28 with PlayBoost), so eking out even 2 or even 4 more hours would have earned it some extra credit.</p><h2 id="jbl-flip-7-review-verdict">JBL Flip 7 review: Verdict</h2><p>Despite its already impressive speaker portfolio, JBL has cranked out another winner in the Flip 7. Vocals and trebles are detailed, crisp, and clean, while its bass performance is dynamic and carries plenty of punch for its size. Plus, its volume capabilities won’t leave you wanting more. Build quality is once again excellent, despite what we’ve come to expect from this major speaker manufacturer. </p><p>Even if you own a Flip 6, I’d argue the sonic and future-proofing upgrades of the Flip 7, namely the updated tweeter redesigned 16mm tweeter dome, lossless playback, and Auracast compatibility, make upgrading worth it. </p><p>Plus, it’s built like a rock, meaning it can survive dips and dunks in sand, dirt, and water, making it perfect for enjoying outdoors or in the backyard. And while the slightly aggressive design isn’t going to suit everyone — it’ll feel out of place at a dinner party — its rough and tumble readiness will be a big hit for many.</p><p>Finally, the Flip 7 cuts a swathe through much of the competition, even some of the more premium rivals — you’re getting a lot of speaker for your money here, so it’s a no-brainer.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 'Expensive doesn’t mean good’: here’s why I’ll be sticking with my $40 speaker over this $200 one ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/expensive-doesnt-mean-good-heres-why-ill-be-sticking-with-my-usd40-speaker-over-this-usd200-one</link>
                                                                            <description>
                            <![CDATA[ I've been testing the Edifier ES60 for a week and while it's a decent speaker, I'm not sure the price is justified... so I'll stick with my Tribit instead. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">95vgaTabr2wiXBhvcdS2GW</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ExWMA3JUGUuQHJZ3PyZdgk-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 30 Jan 2026 09:01:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide, and she&#039;s always on the lookout for the latest tech. She is a lifelong gaming and photography enthusiast, especially interested in wildlife and landscape photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and her Google Pixel 7 Pro. She&#039;s also a licensed drone pilot and instant cameras expert so you&#039;ll find her testing these almost every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/ExWMA3JUGUuQHJZ3PyZdgk-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[An Edifier ES60 and a Tribit StormBox Mini+ Bluetooth speakers]]></media:description>                                                            <media:text><![CDATA[An Edifier ES60 and a Tribit StormBox Mini+ Bluetooth speakers]]></media:text>
                                <media:title type="plain"><![CDATA[An Edifier ES60 and a Tribit StormBox Mini+ Bluetooth speakers]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ExWMA3JUGUuQHJZ3PyZdgk-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>There's a common misconception when it comes to buying tech: if something is expensive or costs a premium, surely it's good. We've all been there. On a random Friday night, you're going through Amazon listings to try and find the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speaker</a> when your eyes land on one that costs nearly $200. You think, "That's pricey! This will be worth the money, surely."</p><p>That couldn't be further from the truth. 'Expensive' doesn't mean 'good,' and it's a myth I constantly try to bust when speaking with friends and potential buyers, and it's what my reviews strive to do. Recently, I tested the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review">Edifier ES60</a> which, at first glance, looks like a premium speaker worth the premium it clearly costs: $199 doubloons. And you'd be half-right.</p><div class="product"><a data-dimension112="8567a2b9-bf6f-494b-87f0-ca4373e563d9" data-action="Deal Block" data-label="If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass, but its poor battery life, limited EQ options, and underwhelming vocals might not be for everyone." data-dimension48="If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass, but its poor battery life, limited EQ options, and underwhelming vocals might not be for everyone." data-dimension25="$199" href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1455px;"><p class="vanilla-image-block" style="padding-top:68.93%;"><img id="7xLfZrA2tj28PzCnqnP5HY" name="ES60-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/7xLfZrA2tj28PzCnqnP5HY.jpg" mos="" align="middle" fullscreen="" width="1455" height="1003" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass, but its poor battery life, limited EQ options, and underwhelming vocals might not be for everyone.<a class="view-deal button" href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow" data-dimension112="8567a2b9-bf6f-494b-87f0-ca4373e563d9" data-action="Deal Block" data-label="If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass, but its poor battery life, limited EQ options, and underwhelming vocals might not be for everyone." data-dimension48="If you fancy a retro-looking speaker with modern features, the Edifier ES60 should be right up your street. Built extremely well and sporting a premium design, the ES60 features customizable LED lighting that lights up your desk. It’s packed with features and delivers punchy bass, but its poor battery life, limited EQ options, and underwhelming vocals might not be for everyone." data-dimension25="$199">View Deal</a></p></div><p>If you're familiar with Marshall speakers, you'd probably quickly catch on that the ES60 looks a little like the <a href="https://www.tomsguide.com/audio/marshal-emberton-iii-review">Marshall Emberton III</a> — a black body with gold accents and subtle branding. And it looks great! 10/10 to Edifier in the design department. But the ES60 has some notable drawbacks, and there are a few things that compel me to stick with my much cheaper <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a>.</p><h2 id="razzle-dazzle-light-show">Razzle-dazzle light show</h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/WY5VHxdYTXC3ybFo5wXC6g.jpg" alt="A black Edifier ES60 Bluetooth speaker" /><figcaption>Edifier ES60.<small role="credit">Tom's Guide</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/uqaMLWv6DSzWsGfEdEFot5.jpg" alt="Tribit StormBox Mini+ speaker" /><figcaption>Tribit StormBox Mini+.<small role="credit">Tom's Guide</small></figcaption></figure></figure><p>The Edifier ES60 is a good-looking speaker, covered in soft faux leather, but that isn't even its best aesthetic feature. There is an LED strip that runs the length of the speaker's underside, and it lights up the surface it's sitting on, creating a bit of an ambience or vibe. It looks stunning and definitely adds to the "premium" factor.</p><div class="product"><a data-dimension112="29a2e5f4-2648-4364-a530-770605d5dbb9" data-action="Deal Block" data-label="Retailing for just $39, this speaker boasts fantastic and powerful bass response, plus detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing which means it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound." data-dimension48="Retailing for just $39, this speaker boasts fantastic and powerful bass response, plus detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing which means it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound." data-dimension25="$39" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1480px;"><p class="vanilla-image-block" style="padding-top:101.35%;"><img id="iRvkqAH3YBcTTf4zRa7AdC" name="Tribit-StormBox-Mini-Plus-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/iRvkqAH3YBcTTf4zRa7AdC.jpg" mos="" align="middle" fullscreen="" width="1480" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Retailing for just $39, this speaker boasts fantastic and powerful bass response, plus detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing which means it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound.<a class="view-deal button" href="https://www.amazon.com/Tribit-StormBox-Bluetooth-360%C2%B0Surround-Waterproof/dp/B0DSPCW5M5/" target="_blank" rel="nofollow" data-dimension112="29a2e5f4-2648-4364-a530-770605d5dbb9" data-action="Deal Block" data-label="Retailing for just $39, this speaker boasts fantastic and powerful bass response, plus detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing which means it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound." data-dimension48="Retailing for just $39, this speaker boasts fantastic and powerful bass response, plus detailed vocals. It also sports reactive LED lighting that’s fun to watch, and IPX7 waterproofing which means it can be used poolside or in the shower. For the money, I recommend buying two so you can take advantage of the dreamy stereo sound." data-dimension25="$39">View Deal</a></p></div><p>You know what else features integrated lighting? The much, much cheaper Tribit StormBox Mini+ which I use nearly every day at home — and when I'm not using it, my partner is. On this speaker, the LED lighting runs along the length of the passive radiator, and unlike on the ES60, the StormBox Mini+'s LED lighting reacts and dances to the music, so you get a sound and light show all in one.</p><p>Both speakers are compact but the ES60 is much heavier (2.29lbs) than the StormBox Mini+ (19.2oz), but of course, this would be an unfair comparison as the former is designed to sit on a coffee table or a desk. The latter is more portable, so you can take it on trips with you. The one I'd choose, you ask? The StormBox Mini+, any day. And there's a good reason for it...</p><h2 id="looks-can-be-deceiving">Looks can be deceiving</h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/svdNZfRw5nVGxgWhjMo44g.jpg" alt="A black Edifier ES60 Bluetooth speaker" /><figcaption>Edifier ES60.<small role="credit">Tom's Guide</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/nzE8vbzxwbdc8VQYDhQ8o5.jpg" alt="Tribit StormBox Mini+ speaker" /><figcaption>Tribit StormBox Mini+.<small role="credit">Tom's Guide</small></figcaption></figure></figure><p>There's no point in buying a speaker — whether that's a cheap or expensive one — if it doesn't reproduce sound well<em>. </em>The Edifier ES60 sounds... good. The StormBox Mini+ sounds <em>great. </em>Thing is, the ES60 does a fantastic job of reproducing basslines with plenty of oomph and low-end impact. Percussion instruments don't sound tinny either, and there's lots of warmth for you to indulge in.</p><p>But the ES60 falls way behind the StormBox Mini+ when it comes to delivering well-rounded sound, as the vocals feel all over the place, with transitions between low hums and high-pitched "coos" sounding unclean. The StormBox Mini+, on the other hand, surprisingly handles vocals beautifully. I say it's surprising because it costs just under $40! Read all about my in-depth audio analyses in my <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a> and <a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review">Edifier ES60 reviews</a>.</p><p>This isn't to say that the StormBox Mini+ is perfect, by the way. Given the speaker's tiny size, you'll experience some sound distortion when playing music at near-100% volume. This speaker is <em>small, </em>let's give it some credit. The ES60 doesn't suffer from this issue though, if distortion past the 80% volume mark is a dealbreaker for you (though it really shouldn't be).</p><h2 id="does-the-edifier-es60-do-anything-better">Does the Edifier ES60 do anything better?</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="s6FpLDwBame9kRnQJM5kQg" name="Edifier_ES60_ 3.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/s6FpLDwBame9kRnQJM5kQg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I've sung so many praises of the Tribit StormBox Mini+ that you may be wondering if the Edifier ES60 is good at <em>anything. </em>It is, actually! Aside from desk-shaking bass and pretty looks, the ES60 has other things going for it too. You get a USB-C port for hi-res wired playback, IP66 waterproofing and dustproofing, and Bluetooth 5.4 with multipoint connectivity.</p><p>You also get up to 9 hours of battery life which may sound good but, again, the StormBox Mini+ upstages the ES60 here. Tribit's offering can last up to 12 hours between charges, making it the better choice if you want longer run time. And while the ES60 supports the most basic SBC codec, the StormBox Mini+ supports AAC which offers richer detail and better compression if you're using an iPhone or other Apple device.</p><h2 id="it-all-comes-down-to-what-you-value-more">It all comes down to what you value more</h2><figure role="gallery"><figure><img src="https://cdn.mos.cms.futurecdn.net/Ec2AM8gqUgSPQUUtFhnx3g.jpg" alt="A black Edifier ES60 Bluetooth speaker" /><figcaption>Edifier ES60.<small role="credit">Tom's Guide</small></figcaption></figure><figure><img src="https://cdn.mos.cms.futurecdn.net/v3ihymQmuyduajDk6i34v5.jpg" alt="Tribit StormBox Mini+ speaker" /><figcaption>Tribit StormBox Mini+.<small role="credit">Tom's Guide</small></figcaption></figure></figure><p>At the end of the day, it all comes down to the features you want and value most. Do you want a cutesy, colorful, poolside, portable speaker? Get the Tribit StormBox Mini+. You want a serious-looking, showoff-worthy centerpiece? The Edifier ES60 is for you. Desk-rattling bass? Either will suffice.</p><p>But which speaker offers better value for money? You see, the ES60 faces a lot of fierce competition from heavy hitters like Marshall, JBL and Bose. All three brands <em>also </em>have speakers that are in the same price range (sometimes cheaper, in fact), so why wouldn't you just buy one from them? Personally, I don't think the ES60 justifies the steep asking price. It's good and it could have been great, but it isn't, so I don't see why you'd drop a cool $200 on it.</p><p>The StormBox Mini+, on the other hand, fully justifies the asking price of $40. It's forty dollars. Bass sounds powerful and not booming; vocals sound crystal clear with smooth transitions between different pitches; and the treble isn't overzealous.</p><p>My job is to ensure you don't regret the money you spend, and that you make a well-informed decision before purchasing something. My two cents? It's the StormBox Mini+ all the way, all day, any day.</p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-X1gjoW"></div>                            </div>                            <script src="https://kwizly.com/embed/X1gjoW.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review">'More than just a pretty face’: the Edifier ES60 is a fantastic speaker... with a couple of compromises</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">This Bluetooth speaker sounds so good my partner thought it was Bose — but it costs only $39</a></li><li><a href="https://www.tomsguide.com/audio/speakers/edifier-qr65-premium-speakers-from-a-traditionally-budget-brand">‘I didn’t think a traditionally budget brand could make such good premium speakers’ — here’s why the Edifier QR65 are never leaving my desk</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 'More than just a pretty face’: the Edifier ES60 is a fantastic speaker... with a couple of compromises ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/edifier-es60-review</link>
                                                                            <description>
                            <![CDATA[ The Edifier ES60 is a great Bluetooth speaker, delivering punchy bass, and it's packed with features. But its rivals upstage it in more ways than one. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Ajgz3gktmjT2P2nVhGmczg</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/aAGeCMC3VzGdfeoKDXoz9g-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 28 Jan 2026 10:49:31 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:26 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide. She is a lifelong gaming and photography enthusiast, especially interested in wildlife photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and the Fujifilm X-T50. She&#039;s also a licensed drone pilot and cameras expert so you&#039;ll find her testing those nearly every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/aAGeCMC3VzGdfeoKDXoz9g-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A black Edifier ES60 Bluetooth speaker]]></media:description>                                                            <media:text><![CDATA[A black Edifier ES60 Bluetooth speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A black Edifier ES60 Bluetooth speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/aAGeCMC3VzGdfeoKDXoz9g-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Edifier has been on a roll recently, with its products having earned stellar ratings from the reviews team at Tom’s Guide. I’d just finished reviewing the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/edifier-qr65-review">Edifier QR65</a> computer speakers when I picked up the Edifier ES60, and I was expecting to be blown away. Alas, I was not. Don’t get me wrong: the ES60 is excellent, but it takes a lot to earn a spot among the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> — especially when it’s priced more or less the same as a Marshall and JBLs.</p><p>The ES60 excels at delivering punchy bass with plenty of warmth and low-end impact, and there are many features at play, such as USB-C passthrough and customizable LED lighting. It sports a premium, retro-style design, and the build quality is top-notch. But if you want nuanced vocals or better battery life, look elsewhere.</p><p>For the complete breakdown, read my full Edifier ES60 review.</p><h2 class="article-body__section" id="section-edifier-es60-review-cheat-sheet"><span>Edifier ES60 review: Cheat sheet</span></h2><ul><li><strong>What is it? </strong>A wireless Bluetooth speaker with 360-degree sound, integrated LED lighting and USB-C passthrough</li><li><strong>Who is it for? </strong>Anyone who wants punchy bass in a portable speaker, and doesn’t mind the price tag</li><li><strong>How much does it cost? </strong><a href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow">$199</a> / <a href="https://www.amazon.co.uk/Edifier-Bluetooth-Waterproof-Dustproof-360-degree/dp/B0F8J3B2SX/" target="_blank" rel="nofollow">£119</a></li><li><strong>What do we like? </strong>The great build quality, retro-style design, meaty bass, customizable LED lighting, and the user-friendly companion app</li><li><strong>What don’t we like? </strong>The underwhelming battery life, non-nuanced vocals, and lack of EQ customization</li></ul><h2 class="article-body__section" id="section-edifier-es60-review-specs"><span>Edifier ES60 review: Specs</span></h2><div ><table><thead><tr><th class="firstcol " ><p><strong>Specs</strong></p></th><th  ><p><strong>Edifier ES60</strong></p></th></tr></thead><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow">$199</a> / <a href="https://www.amazon.co.uk/Edifier-Bluetooth-Waterproof-Dustproof-360-degree/dp/B0F8J3B2SX/" target="_blank" rel="nofollow">£119</a></p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, White</p></td></tr><tr><td class="firstcol " ><p><strong>Size</strong></p></td><td  ><p>7.48 x 3.85 x 3.62 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>2.29lbs</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life (rated)</strong></p></td><td  ><p>9 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.4 with SBC, USB-C wired</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP66</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-edifier-es60-review-price-availability"><span>Edifier ES60 review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="svdNZfRw5nVGxgWhjMo44g" name="Edifier_ES60_ 10.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/svdNZfRw5nVGxgWhjMo44g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Edifier is a traditionally budget brand that has been moving into the more “premium” realm with its bookshelf and gaming speakers, and now with Bluetooth speakers too. The Edifier ES60 is priced at <a href="https://www.amazon.com/Edifier-Bluetooth-Dustproof-Waterproof-Connection/dp/B0DTHV3QSW/" target="_blank" rel="nofollow">$199</a> / <a href="https://www.amazon.co.uk/Edifier-Bluetooth-Waterproof-Dustproof-360-degree/dp/B0F8J3B2SX/" target="_blank" rel="nofollow">£119 at Amazon</a>, and as you can see, it’s a little more expensive in the United States of America.</p><p>It’s available in either Black or White and it bears quite a bit of resemblance to a Marshall speaker, with gold accents. It’s priced similarly to one, too. The ES60 is up against heavy lifters, like the <a href="https://www.tomsguide.com/audio/marshal-emberton-iii-review">Marshall Emberton III</a> ($159), the <a href="https://www.tomsguide.com/audio/speakers/jbl-charge-6">JBL Charge 6</a> ($199), the <a href="https://www.tomsguide.com/audio/jbl-just-launched-two-new-bluetooth-speakers-with-lossless-audio-and-my-fave-has-20-hours-of-battery-life">JBL Flip 7</a> ($149), and the <a href="https://www.tomsguide.com/audio/bose-soundlink-flex-2-review">Bose SoundLink Flex 2</a> ($149).</p><p>But can a “budget” brand go toe-to-toe with premium manufacturers? It comes close, as you’ll see in my review below, but if you’re going to be spending nearly $200 anyway, I don’t see why you wouldn’t just get the Emberton III or one of the JBLs.</p><h2 class="article-body__section" id="section-edifier-es60-review-design-controls"><span>Edifier ES60 review: Design & controls</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="GLsWXncYhZyeKjiy53JNQg" name="Edifier_ES60_ 2.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/GLsWXncYhZyeKjiy53JNQg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Premium, retro-style design</strong></li><li><strong>Integrated, customizable LED lighting</strong></li><li><strong>Straightforward controls</strong></li></ul><p>The Edifier ES60 is a treat for the eyes. When I first unboxed it, I immediately noticed that it bore a striking resemblance to the Marshall Emberton III. Not that that’s a bad thing at all; it’s the opposite. The ES60 looks extremely premium, with gold accents and LEDs that illuminate the surface under the speaker.</p><p>Covered in soft faux leather, the ES60 excels in the design department. It doesn’t feel out of place on a coffee table or on your work desk. It’s fairly portable too, measuring 7.5 x 3.9 x 3.6 inches and weighing 2.3lbs. Its weight means you don’t need to worry about unintentionally knocking it about. I’ve also had no trouble carrying it around in my backpack.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WY5VHxdYTXC3ybFo5wXC6g" name="Edifier_ES60_.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/WY5VHxdYTXC3ybFo5wXC6g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Like I said, the ES60 features integrated LED lighting whose color and effect can be customized via the Edifier ConneX app (more on that soon). It creates a bit of ambience and looks delightful. I love how Edifier implements LED or RGB lighting in its speakers, as I’ve seen with the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/edifier-g2000-pro-review">Edifier G2000 Pro</a> ($199) and the <a href="https://www.tomsguide.com/gaming/gaming-peripherals/edifier-qr65-review">Edifier QR65</a> ($499). You can also disable the LED lighting entirely if you want to conserve battery.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="rTTGu57PEo7WBJ2WU7LXNg" name="Edifier_ES60_ 5.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/rTTGu57PEo7WBJ2WU7LXNg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Controls are fairly straightforward, located on the top of the speaker. These enable you to increase or decrease the volume, play/pause playback, switch on/off the LED lighting, and the power button doubles as the input source button. When pressed, they all give good tactile feedback. Nothing to complain about here.</p><h2 class="article-body__section" id="section-edifier-es60-review-features"><span>Edifier ES60 review: Features</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6k9HY6axnc8Wr8gvacWURg" name="Edifier_ES60_ 1.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/6k9HY6axnc8Wr8gvacWURg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Built-in microphone</strong></li><li><strong>Stereo mode with two speakers</strong></li><li><strong>IP66 waterproof and dustproof</strong></li></ul><p>There’s no dearth of features when it comes to the Edifier ES60. Similar to the JBL Charge 6 and the JBL Flip 7, you can pair two ES60s together to create stereo sound. I didn’t have another at my disposal to test this out, but it’s good to know that this feature exists for those who want a more immersive sound experience — or want to soundtrack a large social gathering.</p><p>The ES60 is fitted with a built-in microphone for when you receive calls while listening to music with your smartphone connected. I tested this by speaking to my partner over the speaker, and she said I sounded clear. The integrated noise-canceling technology does well to isolate and amplify your voice in noisy environments, too.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="eM4HEuMBNvJ3nRcpzzHD2g" name="Edifier_ES60_ 9.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/eM4HEuMBNvJ3nRcpzzHD2g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>If you want to use the ES60 while showering, by the pool or in a desert, you can certainly do that as the speaker is IP66-rated. It’s fully protected against dust and high-pressure water jets from any direction, which means you can use it in the shower, no problem. However, the speaker can’t be submerged.</p><p>While IP66 is perfectly fine for most personal use cases, the competition goes further. For instance, the JBL Flip 7 and the JBL Charge 6 are IP68-rated so they can be submerged in 1.5m of water for 30 minutes. Meanwhile, the Marshall Emberton III is IP67-rated so it can survive being in 1m deep water for half an hour too.</p><h2 class="article-body__section" id="section-edifier-es60-review-connectivity-app"><span>Edifier ES60 review: Connectivity & app</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WAXvbHzV2tMcLepbydRQKg" name="Edifier_ES60_ 4.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/WAXvbHzV2tMcLepbydRQKg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Bluetooth 5.4 with SBC</strong></li><li><strong>USB-C wired playback (with passthrough)</strong></li><li><strong>User-friendly app but limited EQ options</strong></li></ul><p>The Edifier ES60 utilizes Bluetooth 5.4 to seamlessly connect to your laptop, smartphone or other Bluetooth-enabled device for wireless playback. It’s worth noting that the only wireless streaming codec the ES60 supports is SBC, so there’s no AAC, LDAC or aptX Adaptive for hi-res, detailed listening over Bluetooth.</p><p>I’m surprised at the lack of codecs. The Marshall Emberton III, the JBL Flip 7 and the JBL Charge 6 all feature SBC <em>and </em>AAC. Bose takes it a step further with the SoundLink Flex 2 by letting you stream audio using aptX Adaptive as long as you have a Snapdragon Sound-certified device.</p><p>What you do get, though, is a USB-C port around the back for more stable listening over a wired connection. Passthrough is a nice addition here — that means the ES60 is charged while it’s plugged into an audio source.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="eGxYwFVWYK9hxPDkDuSW3Z" name="Edifier-ES60-app" alt="Screenshots of the Edifier ConneX app" src="https://cdn.mos.cms.futurecdn.net/eGxYwFVWYK9hxPDkDuSW3Z.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable"><a href='https://cdn.mos.cms.futurecdn.net/eGxYwFVWYK9hxPDkDuSW3Z.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Edifier / Tom's Guide)</span></figcaption></figure><p>Then there’s multipoint connectivity, which enables you to connect the speaker to two devices simultaneously and swap between playback sources as you wish. I tried this with my <a href="https://www.tomsguide.com/phones/google-pixel-phones/google-pixel-10-pro-xl-review">Google Pixel 10 Pro XL</a> and <a href="https://www.tomsguide.com/reviews/macbook-air-2022-m2">MacBook Air M2</a>, and it worked seamlessly. Multipoint connectivity works when the speaker is plugged into, say, a laptop too, as you can change input sources by pressing the power button.</p><p>The ES60 utilizes the <a href="https://play.google.com/store/apps/details?id=com.edifier.edifierconnex&hl=en_GB" target="_blank" rel="nofollow">Edifier ConneX</a> smartphone app for customization, whose user-friendly interface makes it easy to use. Here, you can adjust the lighting, update the firmware, and choose from four EQ presets, such as Music, Game, Movie and Outdoor. However, and this is one of my biggest gripes with the ES60, you can’t customize the EQ to your liking. This means that if you aren’t happy with, say, the vocals (like I wasn’t), you can’t rely on the EQ to save you. Disappointing, really.</p><h2 class="article-body__section" id="section-edifier-es60-review-sound-quality"><span>Edifier ES60 review: Sound quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="6RdnRXgP8kSB7cVqZ2Bm3g" name="Edifier_ES60_ 8.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/6RdnRXgP8kSB7cVqZ2Bm3g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Punchy, desk-shaking bass</strong></li><li><strong>Though it’s small, it doesn’t get overwhelmed</strong></li><li><strong>Vocals lack character</strong></li></ul><p>The Edifier ES60’s design and features wouldn’t matter if its sound quality was trash. Thankfully, it’s not — as long as you don’t mind a bit of a compromise. The ES60’s sound signature is warm, and for a speaker of its size, the bass is powerful and punchy, enough to rattle your desk when playing at high volumes.</p><p>A well-endowed speaker, it’s equipped with dual 22mm tweeters, one mid-bass driver, and a passive bass radiator. The Class-D amplifier delivers 34W of sound and a 360-degree listening experience, so you can hear music from either side of the speaker. I tested the speaker by listening to my usual testing songs on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, the <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service</a> for hi-res audio.</p><p>Good things first. I kicked things off by listening to ‘<a href="https://open.qobuz.com/track/7020287" target="_blank" rel="nofollow">Papercut</a>’ by Linkin Park. Right off the bat, I was able to appreciate both Mike Shinoda’s and Chester Bennington’s raps, with every word sounding clear and discernible. Even though it’s a heavy rock track with high-gain guitars and turntable scratching, the speaker didn’t get overwhelmed, resulting in a well-rounded listening experience.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Ec2AM8gqUgSPQUUtFhnx3g" name="Edifier_ES60_ 6.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/Ec2AM8gqUgSPQUUtFhnx3g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>To test the bass, I listened to MGMT’s ‘<a href="https://open.qobuz.com/album/ezdz7pij8bfnc" target="_blank" rel="nofollow">Little Dark Age</a>’ with its thick, driving bassline. To its credit, the ES60 did a fantastic job of accurately and powerfully reproducing the bassline. Every note plucked is loud and clear, with plenty of warmth and low-end impact. The ES60 also excelled at balancing softer instruments, like a flute, against the double-bass driving kickdrum in Eluveitie’s ‘<a href="https://open.qobuz.com/track/58075634" target="_blank" rel="nofollow">Ambiramus</a>.’</p><p>I then listened to ‘<a href="https://open.qobuz.com/track/58451135" target="_blank" rel="nofollow">Black Madonna</a>’ by Cage the Elephant. The mid-tempo drum beat and percussion sounded steady and not aggressive, giving other instruments room to float on top. The track sounded very good, but the reverbed vocals sounded a bit too scratchy for my liking. This was also the case with Alt-J’s ‘<a href="https://open.qobuz.com/track/159995253" target="_blank" rel="nofollow">Every Other Freckle</a>’ where Joe Newman’s vocals felt a bit all over the place. The transition between his low hums and high-pitched “coos” didn’t feel very clean, the vocals thereby losing their accuracy and clarity.</p><p>Overall, while the ES60 is good for casual listening and does well on the bass front, it’s a little lacking when it comes to treble and vocal accuracy. If you want a dynamic speaker that excels regardless of the song or genre you’re listening to, I’d recommend either the Marshall Emberton III or the JBL Flip 7.</p><p><em>Listen along to my review with the Edifier ES60 testing playlist:</em></p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/54414294?zone=GB-en"></iframe><h2 class="article-body__section" id="section-edifier-es60-review-battery-life"><span>Edifier ES60 review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="s6FpLDwBame9kRnQJM5kQg" name="Edifier_ES60_ 3.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/s6FpLDwBame9kRnQJM5kQg.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>9 hours of battery life</strong></li><li><strong>Pales in comparison to rivals</strong></li></ul><p>Edifier claims that on a single charge, the Edifier ES60 can last up to nine hours. In my testing, when the speaker was playing at approximately 70% volume with the LED lighting turned off, it lasted just under nine hours between charges.</p><p>Sounds decent, doesn’t it? It really isn’t, especially when compared to similarly priced rivals. The Bose SoundLink Flex lasts up to 12 hours. The JBL Flip 7 lasts up to 16 hours. The JBL Charge 6 lasts up to 28 hours. The Marshall Emberton III lasts up to 32 hours. All of these speakers cost either the same as or a little less than the ES60. It’s a shame that Edifier hasn’t packed a bigger battery into the speaker because its short battery life massively holds it back.</p><p>Also, bear in mind that you’re paying nearly $200 for the ES60. I’ve tested cheaper speakers that have lasted longer. For instance, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-mini-plus-review">Tribit StormBox Mini+</a> retails for $39 and still manages to upstage the ES60 with its 12-hour battery life. Even the <a href="https://www.tomsguide.com/audio/speakers/bluetooth-speakers/earfun-uboom-l-review">EarFun UBoom L</a> ($79) which also sports a rectangular design comfortably lasts over 16 hours on a single charge. What gives, Edifier?</p><h2 class="article-body__section" id="section-edifier-es60-review-verdict"><span>Edifier ES60 review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="aAGeCMC3VzGdfeoKDXoz9g" name="Edifier_ES60_ 7.JPG" alt="A black Edifier ES60 Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/aAGeCMC3VzGdfeoKDXoz9g.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Edifier ES60 is visually stunning, with customizable LED lighting that lights up the surface underneath, and retro styling that, frankly, makes it look like a Marshall speaker. Tactile controls, gold accents, and features such as USB-C passthrough take it from being just any other speaker by a traditionally “budget” brand. It packs satisfying, punchy bass that’s sure to keep you headbanging for days on end.</p><p>But looks aren’t everything as the ES60 struggles to keep pace with heavy hitters, the likes of JBL and Marshall. While the bass is excellent for its size, vocals lack nuance and character, EQ customization is limited, and the 9-hour battery life is a significant Achilles’ heel.</p><p>If you don’t mind these tradeoffs, then you’ll love the ES60. It makes for a pretty centerpiece, and the desk-rattling bass is beautiful. But even then, I keep asking myself, “Why wouldn’t you just buy the JBL Flip 7 or the Marshall Emberton III?”</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ IKEA just launched a new Bluetooth speaker lamp that disappears into your decor — here’s why I’ll be buying one ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/home/ikea-just-launched-a-new-bluetooth-speaker-lamp-that-disappears-into-your-decor-heres-why-ill-be-buying-one</link>
                                                                            <description>
                            <![CDATA[ I’ve just discovered IKEA’s new Bluetooth speaker lamp that is the ultimate home upgrade — here’s why. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">QmYeSHVzKGuN83apLC6Z4G</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/qDjyc8Eiy5wJbvt6XKC4u6-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 27 Jan 2026 10:42:32 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Home]]></category>
                                                                                                                    <dc:creator><![CDATA[ Cynthia Lawrence ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/CCuSgQpd5NyZ46CgoF9cva.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ null ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/qDjyc8Eiy5wJbvt6XKC4u6-1280-80.jpg">
                                                            <media:credit><![CDATA[IKEA]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[IKEA KULGLASS two lamp speakers ]]></media:description>                                                            <media:text><![CDATA[IKEA KULGLASS two lamp speakers ]]></media:text>
                                <media:title type="plain"><![CDATA[IKEA KULGLASS two lamp speakers ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/qDjyc8Eiy5wJbvt6XKC4u6-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>When it comes to interior design, my biggest challenge is finding a way to integrate technology into my home's decor without it looking like an eyesore. And just like some of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> around, I wanted something that looked stylish as well as sounding awesome. </p><p>That’s why I was excited to see IKEA’s new <a href="https://www.ikea.com/us/en/p/kulglass-bluetooth-speaker-lamp-red-brown-pink-80605294/" target="_blank" rel="nofollow">KULGLASS Bluetooth speaker lamp for $129</a>. Not only is it a chic way to combine soft lighting and sound, but it will literally blend in with any room style. </p><p>What’s more, this 2-in-1 lamp features an eye-catching design and comes in two bold colors — red, brown/pink, and dark green, to add a pop of color. Here’s why I can’t wait to pick one up. </p><div class="product"><a data-dimension112="7dccbbf1-5a0b-4efb-9f91-7b06750103c0" data-action="Deal Block" data-label="The KULGLASS speaker lamp delivers light, sound, and vibrant color in one product, that is ideal for small spaces. Offering a rich sound quality, it can also be connected with other IKEA speakers so you can enjoy your playlists around the home. Plus, the lamp will instantly jazz up your space with color. These are available in a soft green or a reddish-brown with a hint of pink." data-dimension48="The KULGLASS speaker lamp delivers light, sound, and vibrant color in one product, that is ideal for small spaces. Offering a rich sound quality, it can also be connected with other IKEA speakers so you can enjoy your playlists around the home. Plus, the lamp will instantly jazz up your space with color. These are available in a soft green or a reddish-brown with a hint of pink." data-dimension25="$129" href="https://www.ikea.com/us/en/p/kulglass-bluetooth-speaker-lamp-red-brown-pink-80605294/#content" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:900px;"><p class="vanilla-image-block" style="padding-top:100.00%;"><img id="FHfTS6rVk9EsTKGUT5XeFE" name="IKEA KULGLASS speaker lamp" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/FHfTS6rVk9EsTKGUT5XeFE.jpg" mos="" align="middle" fullscreen="" width="900" height="900" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The KULGLASS speaker lamp delivers light, sound, and vibrant color in one product, that is ideal for small spaces. Offering a rich sound quality, it can also be connected with other IKEA speakers so you can enjoy your playlists around the home. Plus, the lamp will instantly jazz up your space with color. These are available in a soft green or a reddish-brown with a hint of pink.<a class="view-deal button" href="https://www.ikea.com/us/en/p/kulglass-bluetooth-speaker-lamp-red-brown-pink-80605294/#content" target="_blank" rel="nofollow" data-dimension112="7dccbbf1-5a0b-4efb-9f91-7b06750103c0" data-action="Deal Block" data-label="The KULGLASS speaker lamp delivers light, sound, and vibrant color in one product, that is ideal for small spaces. Offering a rich sound quality, it can also be connected with other IKEA speakers so you can enjoy your playlists around the home. Plus, the lamp will instantly jazz up your space with color. These are available in a soft green or a reddish-brown with a hint of pink." data-dimension48="The KULGLASS speaker lamp delivers light, sound, and vibrant color in one product, that is ideal for small spaces. Offering a rich sound quality, it can also be connected with other IKEA speakers so you can enjoy your playlists around the home. Plus, the lamp will instantly jazz up your space with color. These are available in a soft green or a reddish-brown with a hint of pink." data-dimension25="$129">View Deal</a></p></div><h3 class="article-body__section" id="section-why-i-ll-be-picking-up-this-ikea-kulglass-speaker-lamp"><span>Why I’ll be picking up this IKEA KULGLASS speaker lamp</span></h3><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:900px;"><p class="vanilla-image-block" style="padding-top:56.22%;"><img id="jiJoyrNHzUC928q7awAHqP" name="IKEA KULGLASS speaker lamp" alt="IKEA KULGLASS speaker lamp" src="https://cdn.mos.cms.futurecdn.net/jiJoyrNHzUC928q7awAHqP.jpg" mos="" align="middle" fullscreen="" width="900" height="506" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">IKEA KULGLASS speaker lamp </span><span class="credit" itemprop="copyrightHolder">(Image credit: IKEA)</span></figcaption></figure><p>There’s much to like about this KULGLASS Bluetooth speaker lamp. Aesthetically, this is the perfect way to disguise a ‘boxy’ or boring speaker within your decorative lighting scheme. And if you’re already lacking room on your table or bookshelf for both items, this is the ideal space-saver. I also love its chic, colorful design, especially its glass swirl-shaped shade and curved base.</p><p>Sound-wise, it features a multi-speaker mode that allows you to connect a pair or with any of IKEA’s other Bluetooth speakers with this feature. What’s more, these speakers come with Spotify Tap so you can listen to your favourite tunes or podcasts all over the house. Plus, it’s a fun way to get the party started if you’re hosting a gathering — nobody will even notice the speakers are there. What a design dream.</p><p>Given its reasonable price of just $129, I had expected it to cost so much more. Its bargain price tag is certainly a good deal when you consider the 2-in-1 versatility you're getting. So if you want an excellent speaker light that blends seamlessly into your decor, the KULGLASS Bluetooth speaker lamp is an affordable option. </p><p>Check out the rest of IKEA’s Bluetooth speaker lamp range <a href="https://www.ikea.com/us/en/search/?q=bluetooth%20speaker%20lamp" target="_blank" rel="nofollow"><u>here</u></a>. </p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-W0r5KX"></div>                            </div>                            <script src="https://kwizly.com/embed/W0r5KX.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/home/5-ikea-items-id-pick-up-for-my-bathroom-and-theyre-all-under-usd10">5 IKEA items I'd pick up for my bathroom — and they're all under $10</a></li><li><a href="https://www.tomsguide.com/home/home-appliances/should-you-buy-ikea-kitchen-appliances-heres-what-the-experts-say">Should you buy IKEA kitchen appliances?</a></li><li><a href="https://www.tomsguide.com/home/i-organize-my-home-with-these-ikea-storage-items-and-its-never-looked-better">I just upgraded my home with these 5 IKEA items</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ 'Like taking a hot bath in bass': This mid-range Marshall speaker sounds way bigger than it looks ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/marshall-middleton-ii-review</link>
                                                                            <description>
                            <![CDATA[ The Marshall Middleton II is a surprisingly powerful speaker, with strong sound quality, battery life and waterproofing. It's a little on the pricey side, though. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">zNf73gKanBACcvGemnUBKk</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/nojuvFxAUKnW2sXQaQtgwd-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Thu, 22 Jan 2026 13:54:42 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:25 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ peter.wolinski@futurenet.com (Peter Wolinski) ]]></author>                    <dc:creator><![CDATA[ Peter Wolinski ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/stgPfXWY7ukw8J8rfC7vjg.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Peter is a Senior Editor at Tom&#039;s Guide, heading up the site&#039;s Reviews team and Cameras section. Having built gaming PCs since he was 10 (that&#039;s a while ago now) he&#039;s a bit of a nerd about components and hardware. He&#039;s also been an iPhone user since the classic iPhone 4, and a Mac user for well over a decade. Experienced in using and testing all kinds of technology — from phones through to tablets, computers, games consoles, cameras and smart home tech — helping people find the best tech for them (at the best prices) is what Peter does best. A photographer since he bought his first camera (a Fujifilm) in 2015, Peter was previously an Editor for Canon-Europe.com. He then edited the Cameras and How To sections of Tom&#039;s Guide. When he&#039;s not crafting helpful, in-depth reviews, Peter can usually be found out and about honing his architectural photography skills, riding his motorcycle around Welsh mountain roads, telling everyone about his two greyhounds, squeezing a few extra FPS out of PC games or perfecting his espresso shots.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/nojuvFxAUKnW2sXQaQtgwd-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background]]></media:description>                                                            <media:text><![CDATA[The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background]]></media:text>
                                <media:title type="plain"><![CDATA[The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/nojuvFxAUKnW2sXQaQtgwd-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I’m no stranger to a dashing, alternative-style speaker. Not sure I’ve seen one quite as charming as the Marshall Middleton II, though. </p><p>Successor to the original Marshall Middleton, the II brings some key updates to the core running gear, with boosted battery life and some new connectivity goodies sprinkled in for good measure.</p><p>If you need something bigger than Marshall’s compact Emberton, smaller than the chunkier Kilburn, and have circa three hundies going spare in your cash clip, the Middleton II could be one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html"><u>best Bluetooth speakers</u></a> for you.</p><p>Or could it? Find out in my full Marshall Middleton II review.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-cheat-sheet"><span>Marshall Middleton II review: Cheat sheet</span></h2><ul><li><strong>What is it? </strong>A mid-range, mid-sized Bluetooth speaker</li><li><strong>What does it cost?</strong> <a href="https://www.amazon.com/Marshall-Middleton-II-Bluetooth-Speaker/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>$329</u></a> / <a href="https://www.amazon.co.uk/Marshall-Middleton-Bluetooth-Portable-waterproof/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>£269</u></a></li><li><strong>What’s good? </strong>Lots! Looks, build, sound quality, battery, connectivity…</li><li><strong>What’s not? </strong>It’s expensive, and priced confusingly close to the bigger Kilburn</li></ul><h2 class="article-body__section" id="section-marshall-middleton-ii-review-specs"><span>Marshall Middleton II review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/Marshall-Middleton-II-Bluetooth-Speaker/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>$329</u></a> / <a href="https://www.amazon.co.uk/Marshall-Middleton-Bluetooth-Portable-waterproof/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>£269</u></a></p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3; Aux</p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>IP67</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>30 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response rate</strong></p></td><td  ><p>50Hz - 20kHz</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>3.9 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>9.05 x 4.33 x 3.86 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black & brass; cream</p></td></tr><tr><td class="firstcol " ><p><strong>Compatibility</strong></p></td><td  ><p>iOS; Android; Bluetooth & 3.5mm wired devices</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-marshall-middleton-ii-review-price-availability"><span>Marshall Middleton II review: Price & availability</span></h2><p>Now, like most Marshall gear, the Middleton II is expensive, although not extortionate. Especially considering the premium build, effortless styling and solid performance. Marshall is like the BMW of the audio world — premium, a tad luxurious even, yet still attainable to we lay-folk.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="4s7Vht7FxdLKqVhmjG3mTc" name="Marshall_Middleton2_ 10.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/4s7Vht7FxdLKqVhmjG3mTc.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Middleton II costs <a href="https://www.amazon.com/Marshall-Middleton-II-Bluetooth-Speaker/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>$329 at Amazon</u></a>, or <a href="https://www.amazon.co.uk/Marshall-Middleton-Bluetooth-Portable-waterproof/dp/B0FBHTGL16" target="_blank" rel="nofollow"><u>£269</u></a> in ol’ King Charlie’s change. That’s a hell of a lot spennier than its nearest rockstar rival, the $199 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/fender-x-teufel-rockster-cross-review"><u>Fender x Teufel Rockster Cross</u></a> — the only speaker, in my opinion, that gets close to the Marshall lineup’s rogue-ish good looks. As I’ll cover throughout, the Marshall is better in many ways, so it’s definitely worth <em><strong>a</strong></em> premium; it’s just that I doubt it’s worth <em><strong>the</strong></em> premium — $130 is a lot more dough.</p><p>The original Middleton still costs <a href="https://www.amazon.com/Marshall-Middleton-Portable-Bluetooth-Speaker/dp/B0C287KNNH" target="_blank" rel="nofollow"><u>$319 at Amazon</u></a>, though, so for the extra $10, it’s well worth buying the newer model with its improved specs.</p><p>If you’d like similar looks for less, consider the Middleton II’s little sibling, the $149 <a href="https://www.tomsguide.com/audio/marshal-emberton-iii-review"><u>Marshall Emberton III</u></a>. Or there’s the compact <a href="https://www.tomsguide.com/audio/bluetooth-speakers/fender-x-teufel-rockster-go-2-review"><u>Fender X Teufel Rockster Go 2</u></a> at $129. Both garnered high scores in our testing.</p><p>However, there’s a thorn in the Middleton II’s side, price-wise, and that’s its bigger brother, the $379 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review"><u>Marshall Kilburn III</u></a>. The elder bro has bigger sound, a subwoofer, better battery life and isn’t <em>that</em> much larger than the Middleton — not enough to make much real-world difference, anyway. It looks just as good and has more onboard controls. Personally, I’d stretch the extra fifty.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-design-controls"><span>Marshall Middleton II review: Design & controls</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="fP56YmN5LQEqdm5RghQjQd" name="Marshall_Middleton2_ 8.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/fP56YmN5LQEqdm5RghQjQd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Middleton II looks exactly the same as its predecessor, about which I’ve no complaints. Honestly, I’ve never been prouder to bring a Bluetooth speaker along to a party. I thought my Rockster Cross was a looker, but it’s a 7-at-best versus the Middleton.</p><p>Stick this thing in the middle of a table of people, and they go crazy for it. Ever been out to a bar with a really good-looking friend? You notice them getting all the limelight, people stopping and staring, chatting to them, that kind of thing. Well, that’s what it’s like with the Middleton II. Bring it to a gathering and, before you know it, your comrades are ogling it, fawning over it, even stroking it. I caught one of my friends frowning at it, clearly navigating some internal struggle about stealing the thing.</p><p>The Middleton II is built beautifully, too. Pure Marshall. It doesn’t have quite the same ruggedness of the Rockster Cross and its impact-resistant rubber coating, but the Middleton II looks built to last, all the same. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="8TeV5FLWvuyKkGvrqyoeUd" name="Marshall_Middleton2_ 5.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/8TeV5FLWvuyKkGvrqyoeUd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>At 3.9lbs and 9 x 4.3 x 3.8 inches, the Middleton II is more or less the same size and weight as the OG. That isn’t especially large or heavy for a mid-sized Bluetooth speaker, either. Marshall supplies the Middleton II with a wrist strap and (although I wouldn’t want it dangling there on a hike or for an extended period) it isn’t weighty enough for that concept to seem entirely silly. </p><p>The Middleton II is IP67 rated, meaning it’ll essentially withstand anything except being chucked into the deep end of a pond. The 6 in 67 means it’s fully dustproof, too, — a beach-goer’s delight. </p><p>Controls-wise, things are exceedingly simple, while at the same time offering a fairly high level of onboard control — as far as Bluetooth speakers go, anyway. Again, it’s all the same as the original Middleton: there’s a four-way circular knob up top for playback controls, there are power and connectivity buttons, then two sets of up/down buttons for bass and treble adjustments. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="9SvrTysKLn72MsBJbrJXZd" name="Marshall_Middleton2_ 9.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/9SvrTysKLn72MsBJbrJXZd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The latter two, in particular, are very handy. There’s a full custom EQ to play with in the app, but so long as you can settle with mids sounding how they sound, you’ve got everything else you need onboard for quick tweaks to highs and lows — <em>sans</em> smartphone.</p><p>For control <em>avec</em> smartphone, the Marshall app is excellent. It’s smooth, reliable and well-laid-out. The app can be used to update firmware, check precise battery life and adjust the 5-band EQ.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-features-connectivity"><span>Marshall Middleton II review: Features & connectivity</span></h2><p>While the Middleton II’s design has stayed the same as its predecessor, there are some sizable upgrades under the hood, particularly in the connectivity department. The Bluetooth version has increased from 5.1 in the OG model to 5.3, a modest upgrade which doesn’t affect data transfer rates but brings more efficient power consumption (which I’ll cover more in the battery section below) and increased connection stability at range.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="x8eJDMEkf8RoSpPnzEooNd" name="Marshall_Middleton2_ 11.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/x8eJDMEkf8RoSpPnzEooNd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>On the topic of range, the Middleton II’s Bluetooth range has jumped to 200 feet / 60 meters from the OG model’s 30 feet / 10 meters — a huge delta. 33 feet is also where the Middleton II’s bigger sibling, the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review"><u>Marshall Kilburn III</u></a>, tops out. Now, 200 feet is obviously a best-case scenario, assuming clear line of sight etc, but put it this way: I haven’t been <strong>able</strong> to break connection with the Middleton II in my house or garden.</p><p>Codec-wise, Marshall has added AAC to the OG Middleton’s standalone SBC codec, allowing higher quality playback. There’s now also the LC3 codec, for lower power consumption with similar or higher perceived audio quality than SBC.</p><p>There’s an aux input for wired playback if you’d like to play lossless, although I’d argue that for a party speaker’s primary purpose, sheer fidelity is not the chief priority. Next to the jack is an input/output USB-C port for charging the Middleton and/or refuelling other devices from it.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-sound-quality"><span>Marshall Middleton II review: Sound quality</span></h2><p>I’d not blame you for suspecting a speaker this pretty of being all bluff and no aces. Thankfully, that isn’t the case. </p><p>Like its predecessor, the Middleton II packs dual ⅗-inch tweeters and dual three-inch woofers, with two passive radiators to further amplify the sound from the main drivers. This time, though, the main drivers are neodymium magnetic versus the dynamic drivers of the OG unit, resulting in richer bass (in theory, anyway). Importantly, the amps for the main woofers have been boosted from 20W to 30W, for extra bass punch and more loudness. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Lksaj8aYywaFyGBSTNG75d" name="Marshall_Middleton2_.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/Lksaj8aYywaFyGBSTNG75d.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>And for its size, this thing is fairly loud. Indoors, it has no issue soundtracking gatherings and small parties. Admittedly, in my thirties now, those gatherings are a little quieter than they used to be, but for small gardens and one-to-two room parties, the Middleton II is eminently suitable. For larger indoor or outdoor spaces, though, I’d check out the bigger Kilburn III. And there’s the enormous <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review"><u>Marshall Bromley 750</u></a> party speaker if it’s a car park or something needs filling.</p><p>The Middleton II’s sound separation isn’t bad. It’s obviously got nothing on a set of the <a href="https://www.tomsguide.com/us/best-headphones,review-1988.html"><u>best headphones</u></a>, and uber-spacious tracks like Mk.Gee’s ‘<em>Dream Police</em>’ sound a tad claustrophobic. But I had to pay attention to care. And hey, it’s a Bluetooth speaker, remember? It isn’t really meant for detailed listening.</p><p>There’s stereo playback, too, which is OK. I played ‘<em>Moving in Stereo</em>’ by The Cars, which leans heavily on left and right stereo separation, especially noticeable in its opening section. As the riff came in, I could just about make it out as coming from the right-hand channel, followed quickly by Benjamin Orr’s vocals through the left. But only just. Again, though, it’s a compact speaker.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="QNhQbq49vHLDM99PBotAed" name="Marshall_Middleton2_ 3.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/QNhQbq49vHLDM99PBotAed.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Marshall promises 360-degree sound, suggesting you can sit anywhere around the speaker and still get the full effect. That’s mostly true. Sitting in front or behind, I had great difficulty working out any difference, although at the sides there’s a definite muting of the sound. Sat around a table with friends, though, would I care? No.</p><p>The Middleton II’s default ‘Marshall’ EQ profile is deliberately neutral. I wanted a little extra brightness from Stewart Copeland’s ferocious cymbals in The Police’s ‘<em>Truth Hits Everybody</em>’, which felt uncharacteristically un-piercing — nothing a little EQ tweaking couldn’t fix, though. Otherwise, I had very few issues with the high-up stuff.</p><p>Mid tones are well-pronounced, suiting guitar- and kick-drum-heavy rock tracks — unsurprising for a Marshall speaker. Zeppelin’s ‘<em>Whole Lotta Love</em>’ riff sounds as gravelly and powerful as it ought to, while the conjoined riffs of Melvins' ‘<em>Honey Bucket</em>’  are just as thick and sludgy as god intended.</p><p><em>Listen along to my testing playlist below:</em></p><iframe allow="" height="390" width="400" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/43705610?zone=GB-en"></iframe><p>I was particularly impressed by the Middleton II’s low frequency response, which suits the speaker especially well to bassy electronica. I could feel the sumptuous lows of Dusky’s ‘<em>Stick By This</em>’ warming my bones; like taking a hot bath in bass. And in Burn Water’s deep, melancholic ‘<em>Ikigai’</em>, it was more of the same — a rich, tight and distortion-free performance.</p><p>Skream’s <em>‘Sub Island’</em><em><strong> </strong></em>is my go-to for sub-bass testing — a veritable speaker ruiner, in case that wasn’t immediately obvious from the eponym. The track is almost entirely sub-bass, so the fact I could hear anything besides the drum track at all on a speaker this size had me impressed. The ground wasn’t shaking, but the frequencies themselves were all there. For thicker and more powerful sub-bass, though, you’ll need something endowed with a sub-woofer, like the Kilburn III or the $499 <a href="https://www.tomsguide.com/audio/brane-x-review"><u>Brane X</u></a> (my daily driver) and its 9-inch magnetic sub. </p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-microphone-quality"><span>Marshall Middleton II review: Microphone quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="UfGUbv7Fdhpuywp7bnc7wd" name="Marshall_Middleton2_ 7.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/UfGUbv7Fdhpuywp7bnc7wd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="caption-text">The Middleton II's microphone sits just under the central control knob. </span><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Unlike its predecessor, the Middleton II features a microphone, allowing you to take calls through the speaker. The microphone is pretty good, too, although obviously its performance depends on how close you are to it. </p><p>Within a meter of the speaker, the microphone performs respectably on calls. My wife reported that my voice sounded clear, with the full spectrum of my vocals relayed well, from the deeper tones through to higher notes when I whispered. Dropping back further than a few feet from the speaker and my voice started to sound echoey, as if I were on speakerphone (which, well, I was). </p><p>I can see this being a useful feature during gatherings, allowing a group of friends to all join in and take a call. It also gives the Middleton II workplace conferencing capability — hilariously at odds with its edgy, alternative styling.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-battery-life"><span>Marshall Middleton II review: Battery life</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iXauTdtB4XcKe3CNRqnBEd" name="Marshall_Middleton2_ 4.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, being plugged into a USB-C cable, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/iXauTdtB4XcKe3CNRqnBEd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>The Middleton II’s battery life is its <em>pièce de résistance. </em>30 hours, according to Marshall, and I can vouch for it. After pushing 20 hours of mixed-volume use across several small gatherings and numerous testing sessions, I still had 32% of battery left.</p><p>This is a major improvement on the already respectable 20-hour battery life of the original Middleton and almost double the 16-hour battery life of my Fender x Teufel Rockster Cross speaker. If you want the best-of-the-best battery-wise, though, then you’ll have to front the extra 50 bucks for the Kilburn III.</p><p>The Middleton II also features USB-C power output, so you can charge your phone or other devices from it. This is super handy when going on camping trips, as it saves you needing to bring a separate power bank.</p><h2 class="article-body__section" id="section-marshall-middleton-ii-review-verdict"><span>Marshall Middleton II review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="nojuvFxAUKnW2sXQaQtgwd" name="Marshall_Middleton2_ 6.JPG" alt="The Marshall Middleton II Bluetooth speaker in Black and Brass, on a stone surface with a blue wall in the background" src="https://cdn.mos.cms.futurecdn.net/nojuvFxAUKnW2sXQaQtgwd.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p>Ah, the eponymous middle child, cursed with middle-child syndrome. The Marshall Middleton II is a decent little (kinda) speaker. If you need something more than the Emberton III — you’re soundtracking more than a picnic in the park or studying in your dorm room — the Middleton will do the job. It’s loud enough for small gatherings, and the sound itself is fairly impressive. The battery life is excellent, the build quality sublime, the aesthetics jaw-dropping.</p><p>The only problem is its bigger brother, the Kilburn III, which is bigger for the better in most ways: bigger sound, bigger woofer, and only marginally bigger ($50) price tag. The Middleton II still has the upper hand with its impressive connectivity range and better waterproofing, though, so it’ll really depend on your specific needs and what you value most.</p><p>Regardless, I seriously doubt you’ll be disappointed by the middle kiddo. If you chose to save the $50, I get it.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ JLab JBuds Party review: A meatier portable speaker, but at what cost?  ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jlab-jbuds-party-review</link>
                                                                            <description>
                            <![CDATA[ The JLab JBuds Party is a mid-sized budget speaker with LED lights and party mode, but the sound quality doesn’t do enough to justify the increased price. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">6X9jCtGvD7Wp7MGt9K7vuT</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/vAmg9tbi4igUbXm4menoCi-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 09 Jan 2026 12:29:06 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:22 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ erin.bashford@futurenet.com (Erin Bashford) ]]></author>                    <dc:creator><![CDATA[ Erin Bashford ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/rLvJvJVZx43hEzSsJy3BpL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Erin Bashford is a senior reviews writer at Tom’s Guide. She has a Master’s in Broadcast and Digital Journalism from the University of East Anglia and 7 years of experience reviewing music and events for various publications. She has edited publications such as Outline Magazine’s Guide to Norwich, and she has written for a number of music magazines and websites such as Clash Magazine, Outline Magazine and Dork Magazine. She has a strong interest in audio gear and the music world. &lt;/p&gt;&lt;p&gt;As an ex-barista, Erin is passionate about coffee tech. She also loves finding the best cooking hacks and kitchen appliances, including her beloved Instant Pot. &lt;/p&gt;&lt;p&gt;In her spare time, you can find her reading, practising yoga, hiking, writing fantasy novels, or stressing over NYT Games.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/vAmg9tbi4igUbXm4menoCi-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[the jlab jbuds party speaker with LED rainbow lights photographed against a blue background]]></media:description>                                                            <media:text><![CDATA[the jlab jbuds party speaker with LED rainbow lights photographed against a blue background]]></media:text>
                                <media:title type="plain"><![CDATA[the jlab jbuds party speaker with LED rainbow lights photographed against a blue background]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/vAmg9tbi4igUbXm4menoCi-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Some of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best Bluetooth speakers</a> cost an arm and a leg. The JLab JBuds Party, however, is not one of them. </p><p>At just $69, this Bluetooth speaker is considerably cheaper than JBL, Bose, and Sonos’ competition. However, some sacrifices have been made to keep that price low. Namely, sound quality sacrifices. </p><p>The JBuds Party likely won’t impress anyone more serious than the most casual of listeners, and, remarkably, the $34 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-go-party-review">JLab Go Party</a> sounds <em>better</em>. If I were you, I’d save $35 and go for the cheaper version — but if you want to know more, keep reading this JLab JBuds Party review. </p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-cheat-sheet"><span>JLab JBuds Party review: Cheat sheet</span></h2><ul><li><strong>What is it? </strong>A medium-sized portable-ish speaker from JLab</li><li><strong>What does it cost? </strong><a href="https://www.amazon.com/JLab-Portable-Bluetooth-Full-Range-Waterproof/dp/B0F39X8WY2" target="_blank" rel="nofollow">$69</a> / <a href="https://www.amazon.co.uk/JLab-Portable-Bluetooth-Speaker-Playtime/dp/B0F39X8WY2" target="_blank" rel="nofollow">£59</a></li><li><strong>What do we like? </strong>The LED lights are funky</li><li><strong>What don’t we like? </strong>The $34 JLab Go Party sounds better</li></ul><h2 class="article-body__section" id="section-jlab-jbuds-party-review-specs"><span>JLab JBuds Party review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/JLab-Portable-Bluetooth-Full-Range-Waterproof/dp/B0F39X8WY2" target="_blank" rel="nofollow">$69</a> / <a href="https://www.amazon.co.uk/JLab-Portable-Bluetooth-Speaker-Playtime/dp/B0F39X8WY2" target="_blank" rel="nofollow">£59</a></p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3</p></td></tr><tr><td class="firstcol " ><p><strong>Durability</strong></p></td><td  ><p>IPX6</p></td></tr><tr><td class="firstcol " ><p><strong>Battery</strong></p></td><td  ><p>12 hours (lights off) </p></td></tr><tr><td class="firstcol " ><p><strong>Frequency response rate</strong></p></td><td  ><p>20Hz - 100Hz</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>2.9 pounds</p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>9.8 x 4.1 x 3.4 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Colors</strong></p></td><td  ><p>Black, pink, teal</p></td></tr><tr><td class="firstcol " ><p><strong>Compatibility </strong></p></td><td  ><p>iOS, Android</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jlab-jbuds-party-review-price-availability"><span>JLab JBuds Party review: Price & availability</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="n9Y4pGyxpofE9XNVn4h26i" name="JLAB_JBUDSParty_ 8.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/n9Y4pGyxpofE9XNVn4h26i.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As with other JLab gear, the JBuds Party is affordable. The speaker is just <a href="https://www.amazon.com/JLab-Portable-Bluetooth-Full-Range-Waterproof/dp/B0F39X8WY2" target="_blank" rel="nofollow">$69 from Amazon U.S.</a> and <a href="https://www.amazon.co.uk/JLab-Portable-Bluetooth-Speaker-Playtime/dp/B0F39X8WY2" target="_blank" rel="nofollow">£59 from Amazon U.K.</a>. JLab’s speakers are all budget-friendly: the $19 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-pop-party-review">Pop Party</a>, $34 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-go-party-review">Go Party</a>, and the $199 almost-14-pound <a href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker" target="_blank" rel="nofollow">Epic Party</a>, which rounds off the lineup. </p><p>The JBuds Party is a weird size — it’s in between ~$100-$150 portable speakers like the <a href="https://www.amazon.com/JBL-Flip-Waterproof-Interchangeable-Accessories/dp/B0DMV3BMGP">JBL Flip 7</a> and ~$300 larger boomboxes like the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-xtreme-4-review">JBL Xtreme 4</a>. As a result, there’s little direct competition to compare with. However, the JBuds Party is still hugely cheap in comparison to other options in the bloated Bluetooth speaker landscape. </p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-design-controls"><span>JLab JBuds Party review: Design & controls</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bcZii7yuDhJkyC5yXMBD7i" name="JLAB_JBUDSParty_.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/bcZii7yuDhJkyC5yXMBD7i.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Surprisingly heavy </strong></li><li><strong>Rugged and feels indestructible </strong></li><li><strong>Control dial for volume and play/pause</strong></li></ul><p>As with other JLab speakers, I’m unfortunately not a huge fan of the design. The mesh casing is outdated, and, dare I say, unsightly. Other speaker brands — like JBL and Bose — manage to combine functionality, an IP rating, and design well. In the future, I’d like to see JLab go for a high-quality plastic or metal mesh. </p><p>One of my favorite design aspects is the LED lightshow. As with other JLab speakers, the JBuds Party has a light display. Now, I can’t tell if this light show is supposed to be in sync with the music or not, but I don’t care. Although I wish it were more in rhythm with the beat, I still caught myself getting mesmerized by the flashing lights. </p><p>Another feature I love is the control dial on top of the speaker. Like the JLab Go Party, this control dial can increase and decrease volume, play and pause the music, and activate LabSync, which I’ll discuss in more detail later. </p><p>You can also adjust EQ and skip ahead/back with the tactile buttons beside the control dial, but for me, it’s all about the dial. It’s great that you don’t have to download the app — you can do pretty much everything but install firmware updates with the buttons. This is a pleasant change from JBL speakers, on which EQ is only adjustable in-app. </p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-features-connectivity"><span>JLab JBuds Party review: Features & connectivity</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="YQkxMjB8i4mFCw5DTTFaEi" name="JLAB_JBUDSParty_ 7.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/YQkxMjB8i4mFCw5DTTFaEi.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>LabSync </strong></li><li><strong>Bluetooth 5.3</strong></li><li><strong>Great range </strong></li></ul><p>As with other JLab speakers, the JBuds Party has LabSync (party mode) with up to 100 speakers. I found this easy to set up with my JLab Go Party, and then I had double Carly Rae Jepsen. What’s not to love? LabSync did make the music sound better, but I don’t think you should have to buy two speakers to get decent sound out of a budget speaker. </p><p>The JBuds Party has a slew of expected features: an IP56 rating, which means it’s dustproof and waterproof; customizable EQ in the app; the aforementioned RGB lighting. Although there’s nothing remarkable — like a mic input you’d find on pricier party speakers like the $299 Tribit StormBox Blast 2 — I’m content with the amount of features for the price. </p><p>Connectivity is painless, though, which is often a bugbear with budget audio gear. I was able to connect via Bluetooth in seconds, set up LabSync with no headache, and the range was also really impressive. I went through three doors, through five large rooms, and up and down two flights of stairs, and the speaker didn’t disconnect. </p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-audio-quality"><span>JLab JBuds Party review: Audio quality</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="bXte79CTEMJjt6AcJFQiPi" name="JLAB_JBUDSParty_ 5.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/bXte79CTEMJjt6AcJFQiPi.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>Lackluster bass </strong></li><li><strong>Confused mids and bass fighting for dominance </strong></li><li><strong>The JLab Go Party sounds better</strong></li></ul><p>To test the JLab JBuds Party, I listened to a range of genres on <a href="https://www.tomsguide.com/audio/qobuz-review">Qobuz</a>, our <a href="https://www.tomsguide.com/buying-guide/best-music-streaming-services">best music streaming service for audiophiles</a>. I listened to most of my music with the ‘JLab Signature’ EQ as the ‘Balanced’ and ‘Bass Boost’ distorted the sound even further. </p><p>I played ‘<a href="https://open.qobuz.com/track/62579392" target="_blank" rel="nofollow">Music Sounds Better With You’ by Stardust</a>. This is one of my favorite songs in the whole world, so I know exactly how it should sound. Unfortunately, the JLab JBuds Party struggled to balance the low- and high-end, and the song felt flat. The synth riffs were the only dynamic, lively part of the soundscape. The vocals sounded underwater, and the bass was compressed. </p><p>Next, I played <a href="https://open.qobuz.com/track/17110828" target="_blank" rel="nofollow">‘Immigrant Song’ by Led Zeppelin</a>. Again, this song sounded underwater and muddled, as if the speaker couldn’t decide which aspect of the soundscape to focus on. In the end, this indecisiveness resulted in a muddy bass, scratchy vocals, and inconsistent sound. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="NgGtpC7YLySzbBaZvCVTFi" name="JLAB_JBUDSParty_ 6.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/NgGtpC7YLySzbBaZvCVTFi.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>My usual bass-testing track is ‘<a href="https://open.qobuz.com/track/245075763" target="_blank" rel="nofollow">flight fm’ by Joy Orbison</a>. This track was, again, confused and muddy. As this song is almost entirely bass, I thought it might be able to balance the types of bass, but this wasn’t the case. The deep low-end struggled to proclaim its rightful dominance, falling flat against the hi-hats and midrange, and crackled at the end of the track. </p><p>After listening to a lot of music on the JBuds Party, I opened up the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-go-party-review">JLab Go Party</a> — the JBuds’ Party’s $34 younger sibling — and played the same tracks. Remarkably, the JLab Go Party sounded much, much better. The bass was richer, more mature, and the treble and mids weren’t fighting for control. I would definitely recommend the Go Party over the JBuds Party. </p><p>Unfortunately, the JBuds Party didn’t live up to my expectations, and there are much better speakers for a little more money out there. Instead of spending $69 on this speaker, I’d recommend saving up a little more and getting the $129 (often on sale for $89-$99) <a href="https://www.tomsguide.com/audio/bluetooth-speakers/fender-x-teufel-rockster-go-2-review">Fender x Teufel Rockster Go 2</a> or the <a href="https://www.amazon.com/JBL-Flip-Waterproof-Interchangeable-Accessories/dp/B0DMYQ32SC" target="_blank" rel="nofollow">JBL Flip 7</a> ($149, often on sale for $99-$119).</p><p>Alternatively, save your money and grab the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-go-party-review">JLab Go Party</a> — it’s $34 and performs much the same as the JBuds Party.</p><iframe allow="" height="300" width="1600" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/51911047?zone=GB-en"></iframe><h2 class="article-body__section" id="section-jlab-jbuds-party-review-app"><span>JLab JBuds Party review: App</span></h2><ul><li><strong>JLab app </strong></li><li><strong>EQ customization </strong></li><li><strong>Easy-to-use app</strong></li></ul><p>As you might expect, the JBuds Party speaker is compatible with the JLab app. This is a pretty standard, run-of-the-mill budget audio gear app. I don’t think it’s necessary — which is a good thing. Too often, audio brands lock their best features behind an app, but JLab doesn’t do that. You can enable LabSync and customize the EQs with the on-speaker buttons. </p><p>Here are a few screenshots from the JLab app, so you can see how easy it is to use. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1600px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Z3Z4v6qHZ3VqPuwmzeWEqF" name="jlab jbuds party app screenshots" alt="the jlab jbuds party speaker jlab app compatibility showing the app controls and eq and software updates in the app" src="https://cdn.mos.cms.futurecdn.net/Z3Z4v6qHZ3VqPuwmzeWEqF.png" mos="" align="middle" fullscreen="" width="1600" height="900" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JLab / Future)</span></figcaption></figure><p>As you can see, the UI is clean and navigable, and there are well-signposted controls. I wish there was a little <em>extra</em> in the app to justify me downloading it, but at the end of the day, this is a $69 speaker. Can I ask for much more? I’ve tested some ~$60 audio gear that doesn’t even <em>work</em>. (<a href="https://www.tomsguide.com/audio/headphones/earfun-wave-life-review">EarFun Wave Life</a>, <a href="https://www.tomsguide.com/audio/earbuds/mixx-streambuds-ultra-mini-review">Mixx StreamBuds</a>.)</p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-battery"><span>JLab JBuds Party review: Battery</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="WDVkC9MxbxRw2Cy5JppCDi" name="JLAB_JBUDSParty_ 4.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/WDVkC9MxbxRw2Cy5JppCDi.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><ul><li><strong>12 hours with lights on </strong></li><li><strong>10 hours with lights off </strong></li><li><strong>Listened on low for 8 hours, battery dropped to 40%</strong></li></ul><p>I was quite disappointed to discover that the JBuds Party will only play for 12 hours. The $34 Go Party lasts for 16 hours without needing a charge. I’ve said it before, and I’ll say it again, but if I were you, I’d just get the Go Party. </p><p>The JBL Flip 7 lasts for 16 hours without needing a recharge, the $129 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit StormBox Lava</a> runs for a whopping 24 hours, so the JLab JBuds Party pales in comparison. But, hey, at least it’s still better than the $179 <a href="https://www.tomsguide.com/audio/bluetooth-speakers/sonos-roam-2-review">Sonos Roam</a>, which splutters out after just 10 hours. </p><h2 class="article-body__section" id="section-jlab-jbuds-party-review-verdict"><span>JLab JBuds Party review: Verdict</span></h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vAmg9tbi4igUbXm4menoCi" name="JLAB_JBUDSParty_ 1.JPG" alt="the jlab jbuds party speaker with LED rainbow lights photographed against a blue background" src="https://cdn.mos.cms.futurecdn.net/vAmg9tbi4igUbXm4menoCi.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I could spend another 500 words describing the JLab JBuds Party’s sound quality, but what’s the point? The answer is simple: just get the JLab Go Party. You’ll save yourself $35 and get a better-sounding, more portable speaker out of it. </p><p>While I appreciate JLab’s vision — the JBuds Party is a weighty, louder, still-affordable older sibling to the smaller Go Party and Pop Party — but I don’t think the extra $35 is justified by the sound quality or features.</p><p>If you want a speaker for cheap, skip the JBuds Party. Save your $$$. Grab the JLab Go Party, and thank me later.  </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ This tiny IKEA speaker costs less than a Vegas coffee, sounds great and has a truly awesome special feature ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-tried-ikeas-new-adorable-usd10-bluetooth-speaker-and-its-surprisingly-good-for-the-price</link>
                                                                            <description>
                            <![CDATA[ For less than $10, the IKEA Kallsup Bluetooth speaker is pretty good — and you can pair up to 100 of them together. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">XF3zZtZj53QaJjpZv74y2e</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/V6Rna5RKFDTgQkRkiZNDJC-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 07 Jan 2026 03:43:39 +0000</pubDate>                                                                                                                                <updated>Fri, 09 Jan 2026 10:06:20 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Smart Home]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                    <category><![CDATA[Home]]></category>
                                                                                                <author><![CDATA[ mike.prospero@futurenet.com (Mike Prospero) ]]></author>                    <dc:creator><![CDATA[ Mike Prospero ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/6ZM8mX4UwccqDJTh9gLPqV.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Michael A. Prospero is the U.S. Editor-in-Chief for Tom’s Guide. He oversees all evergreen content and oversees the Homes, Smart Home, and Fitness/Wearables categories for the site. In his spare time, he also tests out the latest drones, electric scooters, and smart home gadgets, such as video doorbells. Before his tenure at Tom&#039;s Guide, he was the Reviews Editor for Laptop Magazine, a reporter at Fast Company, the Times of Trenton, and, many eons back, an intern at George magazine. He received his undergraduate degree from Boston College, where he worked on the campus newspaper The Heights, and then attended the Columbia University school of Journalism. When he’s not testing out the latest running watch, electric scooter, or skiing or training for a marathon, he’s probably using the latest sous vide machine, smoker, or pizza oven, to the delight — or chagrin — of his family.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/V6Rna5RKFDTgQkRkiZNDJC-1280-80.jpg">
                                                            <media:credit><![CDATA[Future]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[IKEA Kallsup]]></media:description>                                                            <media:text><![CDATA[IKEA Kallsup]]></media:text>
                                <media:title type="plain"><![CDATA[IKEA Kallsup]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/V6Rna5RKFDTgQkRkiZNDJC-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>One doesn't necessarily equate IKEA with audio products, but at <a href="https://www.tomsguide.com/news/live/ces-2026-live-latest-news">CES 2026</a>, the company unveiled the Kallsup, a tiny cube-shaped Bluetooth speaker that costs less than $10. If you're around Las Vegas, especially during CES, you'll know that's less than you'll pay for a coffee on the strip.  </p><p>I had a chance to try it out at the show, and for the price, it looks to be if not one of the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">best cheap Bluetooth speakers</a>, then at least a fun little device for kids or teens looking for some inexpensive tunes.</p><p>But that's not all. The Swedish company also showed off its new collection of circular Bluetooth speakers with Spotify functionality starting at $49, which look to make as much a visual statement as an auditory one.</p><div  class="fancy-box"><div class="fancy_box-title">Tom's Guide at CES</div><div class="fancy_box_body"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' ><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ta3dXY62nkc8pUxn65nRLY" name="CES 2025" caption="" alt="CES 2025" src="https://cdn.mos.cms.futurecdn.net/ta3dXY62nkc8pUxn65nRLY.jpg" mos="" link="" align="" fullscreen="" width="" height="" attribution="" endorsement="" class="pinterest-pin-exclude"></p></div></div><figcaption itemprop="caption description" class=""><span class="credit" itemprop="copyrightHolder">(Image credit: Future)</span></figcaption></figure><p class="fancy-box__body-text">Follow all of our <a data-analytics-id="inline-link" href="https://www.tomsguide.com/news/live/ces-2026-live-latest-news">CES 2026 live coverage </a>for the biggest gadget news straight from Las Vegas. And be sure to follow <a data-analytics-id="inline-link" href="https://www.tiktok.com/@tomsguide" target="_blank">Tom's Guide on TikTok</a> for the coolest videos from the show.</p></div></div><p>The Kallsup will be released in April, and will come in three colors: white, green, and pink. Individually, each speaker isn't all that powerful — not surprisingly, the Kallsup isn't the biggest on bass. I listened to a few tunes, and would equate it to a second- or third-generation Echo Dot Mini. However, here's the awesome trick up its sleeve: you can pair up to 100 of IKEA's speakers for some truly epic sound. And at less than ten bucks a pop, you could easily pick up four or five of these little guys and scatter them around your room for wall-to-wall sound. </p><p>The device itself adheres to IKEA's design philosophy: clean and neat. It's two inches on each side, about the same size as a Rubik's Cube. On the top are two buttons: one to pair it via Bluetooth, and one to play/pause/advance your music. </p><p>There aren't any volume controls, nor can I find a way to actually turn the speaker off, though it will turn itself off automatically after a certain period of inactivity. A USB-C port on the back lets you recharge the speaker, but there's no indication of how long the battery will last — and you have to provide your own charging cable.</p><h2 id="ikea-enters-the-smart-home">IKEA enters the smart home</h2><p>The Kallsup was just one of about two dozen smart home devices IKEA showed off at CES, most of which were as inexpensive as the speaker. While many of the gadgets went on sale in December, the show was the first time we saw them up close, Here's a quick rundown of the ones that caught my eye.</p><div class="product"><a data-dimension112="dac6e6fa-f0ad-4457-becb-7f949c2437b4" data-action="Deal Block" data-label="It's not IKEA's first Bluetooth speaker/lamp combo, but the Kulglass' pillowy, rounded top and mesh base certainly stands out for its design. It comes in two versions: a reddish brown base and pink top, or a darn green base and lighter green top." data-dimension48="It's not IKEA's first Bluetooth speaker/lamp combo, but the Kulglass' pillowy, rounded top and mesh base certainly stands out for its design. It comes in two versions: a reddish brown base and pink top, or a darn green base and lighter green top." data-dimension25="$129" href="https://www.ikea.com/us/en/p/kulglass-bluetooth-speaker-lamp-red-brown-pink-80605294/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:87.10%;"><img id="AbZH43SArofZa8URtVhxSX" name="ikea Kulglass" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/AbZH43SArofZa8URtVhxSX.jpg" mos="" align="middle" fullscreen="" width="1000" height="871" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>It's not IKEA's first Bluetooth speaker/lamp combo, but the Kulglass' pillowy, rounded top and mesh base certainly stands out for its design. It comes in two versions: a reddish brown base and pink top, or a darn green base and lighter green top.<a class="view-deal button" href="https://www.ikea.com/us/en/p/kulglass-bluetooth-speaker-lamp-red-brown-pink-80605294/" target="_blank" rel="nofollow" data-dimension112="dac6e6fa-f0ad-4457-becb-7f949c2437b4" data-action="Deal Block" data-label="It's not IKEA's first Bluetooth speaker/lamp combo, but the Kulglass' pillowy, rounded top and mesh base certainly stands out for its design. It comes in two versions: a reddish brown base and pink top, or a darn green base and lighter green top." data-dimension48="It's not IKEA's first Bluetooth speaker/lamp combo, but the Kulglass' pillowy, rounded top and mesh base certainly stands out for its design. It comes in two versions: a reddish brown base and pink top, or a darn green base and lighter green top." data-dimension25="$129">View Deal</a></p></div><div class="product"><a data-dimension112="6699e70c-7557-4675-bf32-118d0c6f2e84" data-action="Deal Block" data-label="limited-edition 11-inch model is $69" data-dimension48="limited-edition 11-inch model is $69" data-dimension25="$49" href="https://www.ikea.com/us/en/p/solskydd-portable-bluetooth-speaker-orange-50605870/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:84.50%;"><img id="KGFqWjUCCNqFM2SPVke78d" name="IKEA SOLSKYDD" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/KGFqWjUCCNqFM2SPVke78d.jpg" mos="" align="middle" fullscreen="" width="1000" height="845" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>While its partnership with Sonos may be ending, IKEA launched a series of circular Bluetooth speakers with some very bold designs. The SOLSKYDD is available in three sizes: the 8-inch model costs $49, a <a href="https://www.ikea.com/us/en/p/solskydd-bluetooth-speaker-green-40605856/" target="_blank" rel="nofollow" data-dimension112="6699e70c-7557-4675-bf32-118d0c6f2e84" data-action="Deal Block" data-label="limited-edition 11-inch model is $69" data-dimension48="limited-edition 11-inch model is $69" data-dimension25="$49">limited-edition 11-inch model is $69</a>, and an <a href="https://www.ikea.com/us/en/p/solskydd-bluetooth-speaker-white-90606325/" target="_blank" rel="nofollow">18-inch model costs $99</a>. All of the speakers can be paired for stereo sound, and they have a Spotify Tap function, which not only plays music from the streaming service, but will also generate playlists based on your preferences.<a class="view-deal button" href="https://www.ikea.com/us/en/p/solskydd-portable-bluetooth-speaker-orange-50605870/" target="_blank" rel="nofollow" data-dimension112="6699e70c-7557-4675-bf32-118d0c6f2e84" data-action="Deal Block" data-label="limited-edition 11-inch model is $69" data-dimension48="limited-edition 11-inch model is $69" data-dimension25="$49">View Deal</a></p></div><div class="product"><a data-dimension112="0bec5656-bbf1-4c50-bc28-da39af8924da" data-action="Deal Block" data-label="This neat little bedside companion tells the time, but you can also tap on its top to display carbon dioxide levels, air quality, and the temperature in your room. And, because it's Matter compatible, you can connect it to other smart home devices." data-dimension48="This neat little bedside companion tells the time, but you can also tap on its top to display carbon dioxide levels, air quality, and the temperature in your room. And, because it's Matter compatible, you can connect it to other smart home devices." data-dimension25="$29" href="https://www.ikea.com/us/en/p/alpstuga-air-quality-sensor-smart-70609396/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1000px;"><p class="vanilla-image-block" style="padding-top:82.80%;"><img id="e6JK3zrJnZWSNE6uDmo7aS" name="IKEA ALPSTUGA" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/e6JK3zrJnZWSNE6uDmo7aS.jpg" mos="" align="middle" fullscreen="" width="1000" height="828" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>This neat little bedside companion tells the time, but you can also tap on its top to display carbon dioxide levels, air quality, and the temperature in your room. And, because it's Matter compatible, you can connect it to other smart home devices.<a class="view-deal button" href="https://www.ikea.com/us/en/p/alpstuga-air-quality-sensor-smart-70609396/" target="_blank" rel="nofollow" data-dimension112="0bec5656-bbf1-4c50-bc28-da39af8924da" data-action="Deal Block" data-label="This neat little bedside companion tells the time, but you can also tap on its top to display carbon dioxide levels, air quality, and the temperature in your room. And, because it's Matter compatible, you can connect it to other smart home devices." data-dimension48="This neat little bedside companion tells the time, but you can also tap on its top to display carbon dioxide levels, air quality, and the temperature in your room. And, because it's Matter compatible, you can connect it to other smart home devices." data-dimension25="$29">View Deal</a></p></div><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-these-are-the-best-ones-ive-used-in-2025">I test Bluetooth speakers for a living — and these are my 3 top picks for 2025</a></li><li><a href="https://www.tomsguide.com/audio/speakers/i-replaced-my-smart-home-speaker-with-this-klipsch-speaker-and-im-never-going-back">I replaced my smart home speaker with this Klipsch speaker — and I’m never going back</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-put-jlab-and-tribits-budget-bluetooth-speakers-to-the-test-and-heres-why-you-need-to-spend-that-extra-usd10">I put these 2 Bluetooth speakers to the test that can go anywhere — here's my top pick under $50</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ LG and will.i.am teaming up on new xboom speakers with longer battery life and AI ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/lg-and-will-i-am-teaming-up-on-new-xboom-speakers-with-longer-battery-life-and-ai</link>
                                                                            <description>
                            <![CDATA[ LG and will.i.am are collaborating on a refreshed xboom Bluetooth speaker lineup with AI integration. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">Qm2scszSN4vS8HnLxvmrKJ</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/ZJFoqKmCR8krpvVNsSmS7S-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Fri, 02 Jan 2026 18:57:48 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ scott.younker@futurenet.com (Scott Younker) ]]></author>                    <dc:creator><![CDATA[ Scott Younker ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/RZsUpqcJ6Uj2q83oCUwNhQ.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Scott Younker is the West Coast Reporter at Tom’s Guide. He covers all the latest tech news, including phones, computing and more. He’s been involved in tech since 2011 covering everything from cameras and swimming pool equipment to the latest gaming consoles and smart TVs. He is on a seemingly never ending hunt to build the easiest to use home media system. &lt;/p&gt;&lt;p&gt;Before Tom’s Guide, Scott worked for publications like &lt;em&gt;Digital Trends, Outdoor Photographer, Dead Beats Panel&lt;/em&gt;, and in a brief detour, &lt;em&gt;America’s Funniest Home Videos&lt;/em&gt;. Yes, he has seen more pratfalls, silly pets and ridiculous home movie fails than is reasonably healthy. &lt;/p&gt;&lt;p&gt;When not writing about the latest devices or advances in chipsets, be sure to ask about Scott about disc golf and sustainability, or just if you’re being cheeky, ask about his noodle arm. If you truly want to get nerdy, bring up board games and his ongoing losing streak. &lt;/p&gt;&lt;p&gt;Scott joined Tom&#039;s Guide in 2024 as the West Coast Reporter. He graduated from the School of Journalism at the University of Oregon with a degree in magazine journalism and a minor in communications. While there he blogged or wrote for several magazines including the Fluxx, Ethos and the Oregon Commentator. He briefly wrote and managed a moderately successful blog focused on web comics. &lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/ZJFoqKmCR8krpvVNsSmS7S-1280-80.jpg">
                                                            <media:credit><![CDATA[LG]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[LG xboom by will.i.am 2026 bluetooth speaker]]></media:description>                                                            <media:text><![CDATA[LG xboom by will.i.am 2026 bluetooth speaker]]></media:text>
                                <media:title type="plain"><![CDATA[LG xboom by will.i.am 2026 bluetooth speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/ZJFoqKmCR8krpvVNsSmS7S-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The biggest tech show of the year, <a href="https://www.tomsguide.com/tag/ces">CES 2026</a>, is right around the corner, and LG is set to debut four new speakers in its xboom Bluetooth speaker series. Designed in collaboration with the artist will.i.am, the new speakers will feature AI integration and update the existing Stage 301, Bounce and Grab speakers.</p><p>The 2026 xboom speakers are supposed to feature "stage-inspired" speakers and a rugged design for outdoor use. LG says the collaboration focuses on "smarter interaction," extended battery life and seamless design.</p><p>“The collaboration with <a href="http://will.i.am/" target="_blank">will.i.am</a> continues to advance our vision for intelligent, expressive sound,” said Lee Jeong-seok, head of the LG Media Entertainment Solution Company’s Audio Business said in a press release.</p><h2 id="ai-integration">AI Integration</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1200px;"><p class="vanilla-image-block" style="padding-top:75.00%;"><img id="Eh2BC9eq7pfRMFYdxqHACW" name="google-home-radio-stations.jpg" alt="radio dial" src="https://cdn.mos.cms.futurecdn.net/Eh2BC9eq7pfRMFYdxqHACW.jpg" mos="" align="middle" fullscreen="" width="1200" height="900" attribution="" endorsement="" class="inline"></p></div></div></figure><p>AI integration comes in the form of FYI.RAidiO, an AI project in the works from will.i.am. The AI radio has AI personas and DJs that let users use conversational prompts to find music. It offers "real-time curation" and location-aware personalization. </p><p>“With FYI.RAiDiO and AI personas, xboom by <a href="http://will.i.am/" target="_blank">will.i.am</a> speakers offer a glimpse into a new way of enjoying audio experience through an inspiring cultural connection with AI," will.i.am. said in a press release.</p><p>The platform launched last year in partnership with Mercedes-Benz, but <a href="https://www.lg.com/us/press-release/now-available-xboom-by-william-with-fyiraidio-the-speaker-that-talks-back" target="_blank">LG introduced FYI.AI </a>in newer versions of the xboom Grab and Bounce speakers back in September with the new "MY Button."</p><h2 id="four-new-speakers">Four new speakers</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:149.90%;"><img id="BEVm5c5Xof8JaQKxAT7q7a" name="xboom Stage 501 will.i.am" alt="LG Xboom by will.i.am" src="https://cdn.mos.cms.futurecdn.net/BEVm5c5Xof8JaQKxAT7q7a.jpg" mos="" align="middle" fullscreen="" width="1920" height="2878" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: LG)</span></figcaption></figure><p>The expanded xboom is getting four new models: the Stage 501, Blast, Mini, and Roc, each meant for different listening settings. </p><p>The Stage 501 is an update to the Stage 301 with a new AI Karaoke Master that can remove or adjust vocals from most any songs, so you can sing along with the song or hit it solo. It comes with 25 hours of playback with the 99Wh swappable battery. It can be set up vertically, horizontally, tilted or on a tripod mount. The speaker has dual woofers, full-range drivers and Peerless tweeters.</p><p>The xboom Blast is the rugged speaker meant for outdoor adventures. It features up to 35 hours of playback with a 99Wh battery. It comes with a side rope handle for travel, along with a rubber top handle.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:3840px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="vRWxr9nb6Y24nP3LYSM3Na" name="xboom-rock-2026-pr-asset-front-view" alt="LG Xboom by will.i.am" src="https://cdn.mos.cms.futurecdn.net/vRWxr9nb6Y24nP3LYSM3Na.jpg" mos="" align="middle" fullscreen="" width="3840" height="2160" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: LG)</span></figcaption></figure><p>LG's xboom Mini features a cube design and up to 10 hours of playback time per charge. With IP67 water- and dust-resistance, it can go anywhere you do, plus the mini features a built-in tripod mount.</p><p>Finally, the xboom Rock is a rugged speaker meant for more intense outdoor activity. It features up to 10 hours of playback and is meant to be reliable even in "challenging outdoor environments."</p><p>The Rock is an upgrade of the older XG2 model with increased power. It can be paired with multiple LG speakers via LE Audio Auracast.</p><h2 id="release-date-and-price">Release date and price</h2><p>LG did not provide pricing or release date details in its press release. However, the company will be at CES 2026 this year with the new speakers, and we hope to receive more information there.</p><p>As for price, the xboom Stage 301 currently sells for $300, while the older LG XG2 sells for $49.99. We expect similar pricing for the newer models, though tariffs and material price hikes might cause a bump.</p><p>Tom's Guide will be at CES this year, so keep us in your tabs to follow along with all the latest tech news coming later this month.</p><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/tvs/lg-just-announced-its-first-micro-rgb-tv-and-its-a-massive-upgrade-with-color-perfection">LG just announced its first Micro RGB TV — and it's a massive upgrade for Mini-LED</a></li><li><a href="https://www.tomsguide.com/tvs/as-a-tv-expert-this-is-what-i-hope-to-see-from-lg-tvs-in-2026-from-cheaper-oleds-to-new-features">As a TV expert, this is what I hope to see from LG TVs in 2026, from cheaper OLEDs to new features</a></li><li><a href="https://www.tomsguide.com/computing/monitors/lg-display-unveils-worlds-first-oled-monitor-with-crazy-high-720hz-refresh-rate-and-response-time-of-just-0-02ms">LG Display unveils world’s first OLED monitor with crazy high 720Hz refresh rate and response time of just 0.02ms</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I test Bluetooth speakers for a living — and these are my 3 top picks for 2025 ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-test-bluetooth-speakers-for-a-living-and-these-are-the-best-ones-ive-used-in-2025</link>
                                                                            <description>
                            <![CDATA[ I’ve been testing a whole bunch of Bluetooth speakers this year, and these are the ones you need in your rotation. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">88qhRQsJ8qmuK5HSvF8P3S</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/weCEb4zgERofApQiTmr5Yj-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Tue, 23 Dec 2025 11:00:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money.She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK online, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews.She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health, and has her own newsletter where she shares reviews of her favorite books, Ashley’s Reading Nook. In previously published work, she has reviewed live music events, books, and wellness products.She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best.In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest fantasy novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/weCEb4zgERofApQiTmr5Yj-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[Klipsch The One Plus Bluetooth speaker in matte black photographed in front of a blue background.]]></media:description>                                                            <media:text><![CDATA[Klipsch The One Plus Bluetooth speaker in matte black photographed in front of a blue background.]]></media:text>
                                <media:title type="plain"><![CDATA[Klipsch The One Plus Bluetooth speaker in matte black photographed in front of a blue background.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/weCEb4zgERofApQiTmr5Yj-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>Testing audio gear is one of the best things about my job. As a huge music fan, I spend a fair bit on attending gigs — so when I listen to my music at home, I want to get as close to that experience as possible. </p><p>Naturally, I’m picky when it comes to the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ive-tested-10-bluetooth-speakers-in-2025-here-are-the-3-id-buy">best Bluetooth speakers</a>. Sometimes I want a speaker that will fill my house with booming bass, and other times I want to make sure it perfectly replicates the vocal flair of my favorite artist. So, after spending many hours testing some of the best audio gear and some of the best Bluetooth speakers, these are the ones that deserve your money.</p><h2 id="the-rugged-speaker">The rugged speaker</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ryja4TD89MLWDNspHawtiZ" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/ryja4TD89MLWDNspHawtiZ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><div class="product"><a data-dimension112="ba732a41-d384-4b60-92a3-d80f42053556" data-action="Deal Block" data-label="The Tribit PocketGo packs one heck of a punch in the sound department, and it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for picnics and hikes. With some minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension48="The Tribit PocketGo packs one heck of a punch in the sound department, and it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for picnics and hikes. With some minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension25="£24" href="https://www.amazon.co.uk/Tribit-PocketGo-Bluetooth-Waterproof-Dustproof/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1382px;"><p class="vanilla-image-block" style="padding-top:77.13%;"><img id="GsxPoacMB7Yd8gVXi33cEi" name="tribit-pocketgo-portable-wireless-blueto-c671ccc9-8153-4e8a-a1cd-d562d77aaafc.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/GsxPoacMB7Yd8gVXi33cEi.jpg" mos="" align="middle" fullscreen="" width="1382" height="1066" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit PocketGo packs one heck of a punch in the sound department, and it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for picnics and hikes. With some minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker.<a class="view-deal button" href="https://www.amazon.co.uk/Tribit-PocketGo-Bluetooth-Waterproof-Dustproof/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="ba732a41-d384-4b60-92a3-d80f42053556" data-action="Deal Block" data-label="The Tribit PocketGo packs one heck of a punch in the sound department, and it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for picnics and hikes. With some minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension48="The Tribit PocketGo packs one heck of a punch in the sound department, and it’s the ultimate rugged speaker. Its IP68 waterproofing and military-grade drop protection make it perfect for picnics and hikes. With some minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension25="£24">View Deal</a></p></div><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a> is the ultimate all-rounder speaker. I can rely on it for every situation, from hiking on the weekends to having a dance party while cooking in the kitchen. The sound quality is great, making my favorite songs sound amazing.</p><p>It has a waterproof rating of IP68, meaning that it can withstand being up to 1.5 meters underwater for 30 minutes without anything wrecking the performance. So if you’re a little clumsy like me, there’s no need to worry because it’s super durable. The MIL-STD-810H durability rating means that the speaker has military-grade drop protection. </p><p>The PocketGo also has a battery life of 20 hours, which is more than enough to get me through my music listening sessions, and I only charge it up once a week. It’s also super compact, measuring just 4.3 x 3.2 x 1.7 inches, so it’s the perfect addition to my backpack when I head out on walks. And it doesn’t weigh me down since it weighs just 7.8 ounces. </p><h2 id="the-boombox">The boombox </h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RiKpvQVuXrCbdsWTcSLvm" name="Tribit StormBox Lava Bluetooth Speaker" alt="Tribit StormBox Lava Bluetooth Speaker photographed in front of a blue background." src="https://cdn.mos.cms.futurecdn.net/RiKpvQVuXrCbdsWTcSLvm.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-stormbox-lava-review">Tribit Stormbox Lava</a> is the speaker I pull out whenever I have guests around in the summer and need to do some outdoor entertaining. A speaker with <em>huge</em> sound is essential in my rotation, and this speaker combines awesome bass performance with a sleek design. </p><p>The bass from this speaker literally shakes the ground around the speaker, and it makes all of my favorite party tunes sound amazing. But the sound profile can even support acoustic tracks, meaning that it can also provide the tunes for around the campfire. </p><p>Just like the smaller Tribit, the Strombox Lava is water and dustproof, with a rating of IP67. The speaker controls are also super simple to use. You can skip tracks using your phone, but you can adjust the volume or enable the bass-enhancing settings using the buttons on the speaker.</p><div class="product"><a data-dimension112="5e22d26e-bd95-4c55-8f75-45ee6bde8f29" data-action="Deal Block" data-label="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but delivers where it counts. The BassX setting really brings out the bass in your tunes. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension48="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but delivers where it counts. The BassX setting really brings out the bass in your tunes. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension25="£99" href="http://amazon.co.uk/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1294px;"><p class="vanilla-image-block" style="padding-top:88.49%;"><img id="SCQ5Bnz24LhfDYUerRGHw3" name="tribit-stormbox-lava-portable-bluetooth--6f47c707-a5d6-48f6-9d4f-c79e7c0b8fc1.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/SCQ5Bnz24LhfDYUerRGHw3.jpg" mos="" align="middle" fullscreen="" width="1294" height="1145" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but delivers where it counts. The BassX setting really brings out the bass in your tunes. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life.<a class="view-deal button" href="http://amazon.co.uk/Tribit-StormBox-Portable-Bluetooth-Waterproof/dp/B0DN5F9BC2" target="_blank" rel="nofollow" data-dimension112="5e22d26e-bd95-4c55-8f75-45ee6bde8f29" data-action="Deal Block" data-label="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but delivers where it counts. The BassX setting really brings out the bass in your tunes. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension48="The Tribit StormBox Lava is a Bluetooth speaker that won't break the bank but delivers where it counts. The BassX setting really brings out the bass in your tunes. It's also tailor-made for the outdoors, with a completely waterproof and dustproof design and up to 24 hours of battery life." data-dimension25="£99">View Deal</a></p></div><h2 id="the-hi-fi-addition">The Hi-Fi addition</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="QLbLLhTroAmbkZfvbh24Tj" name="Klipsch The One Plus" alt="Klipsch The One Plus Bluetooth speaker in matte black photographed in front of a blue background." src="https://cdn.mos.cms.futurecdn.net/QLbLLhTroAmbkZfvbh24Tj.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/klipsch-the-one-plus-review">Klipsch The One Plus</a> speaker is undeniably good-looking and has been the best addition to my home audio setup this year. It needs to be plugged in to the wall, but it offers seriously crazy sound, with a perfect sound profile. </p><p>The sound profile can also be altered with the Klipsch app, where you have the option to create custom EQ settings. Having your phone on hand when using this speaker is essential, as there are minimal controls on the device. You can only control connectivity and volume from the speaker itself, so any song skips need to be done from the app. </p><p>But the connectivity options with this speaker are great, as I have the choice between a Bluetooth connection and an aux input, meaning I’m able to play my music at the highest quality. It sits on my shelf right next to my turntable and has totally enhanced the way I listen to LPs. </p><p>These three speakers are the best rotation for me as I have a portable option, an outdoor performer and a high-quality home speaker.</p><div class="product"><a data-dimension112="3f9a3891-0978-483d-9d00-0e3c2533d968" data-action="Deal Block" data-label="The One Plus speaker by Klipsch" data-dimension48="The One Plus speaker by Klipsch" data-dimension25="£279" href="https://www.amazon.co.uk/Klipsch-The-One-Plus-Black/dp/B0CK8MBL5Z" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1439px;"><p class="vanilla-image-block" style="padding-top:87.91%;"><img id="VS8P7TTZTr2VYueyjZqoGC" name="klipsch-the-one-plus-bluetooth-speaker-b-e9ea3680-2d96-48cc-a578-912c76984b52.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/VS8P7TTZTr2VYueyjZqoGC.jpg" mos="" align="middle" fullscreen="" width="1439" height="1265" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p><a href="https://www.tomsguide.com/audio/bluetooth-speakers/klipsch-the-one-plus-review" data-dimension112="3f9a3891-0978-483d-9d00-0e3c2533d968" data-action="Deal Block" data-label="The One Plus speaker by Klipsch" data-dimension48="The One Plus speaker by Klipsch" data-dimension25="£279">The One Plus speaker by Klipsch</a> has given me the best sound that fills my whole house. It’s clear, loud, and punchy, bringing the vocals to the forefront of the music without losing any of the instruments. The premium, sleek-looking design also makes it a winner for any modern home, and the diverse connectivity options make it a true all-rounder.<a class="view-deal button" href="https://www.amazon.co.uk/Klipsch-The-One-Plus-Black/dp/B0CK8MBL5Z" target="_blank" rel="nofollow" data-dimension112="3f9a3891-0978-483d-9d00-0e3c2533d968" data-action="Deal Block" data-label="The One Plus speaker by Klipsch" data-dimension48="The One Plus speaker by Klipsch" data-dimension25="£279">View Deal</a></p></div><h2 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h2><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/klipsch-the-one-plus-review">Klipsch The One Plus review</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-kilburn-iii-review">I just tested the Marshall Kilburn III — and it's one of the best Bluetooth speakers ever</a></li><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/i-put-jlab-and-tribits-budget-bluetooth-speakers-to-the-test-and-heres-why-you-need-to-spend-that-extra-usd10">I put these 2 Bluetooth speakers to the test that can go anywhere — here's my top pick under $50</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ As a guitarist and an audiophile, this is the all-in-one speaker I’ve been waiting for ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/as-a-guitarist-and-an-audiophile-this-is-the-all-in-one-speaker-ive-been-waiting-for</link>
                                                                            <description>
                            <![CDATA[ The Marshall Bromley 750 is the British brand's first-ever party speaker, and more than that, it's a guitar amp and a karaoke machine, and I love it. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">9fNnq72dQFQJapUsJHJA6S</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/fvueVyQYtXYk4bq2B6HHuG-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sun, 21 Dec 2025 10:45:00 +0000</pubDate>                                                                                                                                                                                                                                <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ nikita.achanta@futurenet.com (Nikita Achanta) ]]></author>                    <dc:creator><![CDATA[ Nikita Achanta ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/oXuvixDz99SbZp9z8Uoor3.png ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Nikita is a Senior Writer on the Reviews team at Tom&#039;s Guide, and she&#039;s always on the lookout for the latest tech. She is a lifelong gaming and photography enthusiast, especially interested in wildlife and landscape photography. Having worked as a Sub Editor and Writer for Canon EMEA, she’s a bit of a grammar nerd (and a supporter of the Oxford comma), and has also interviewed photographers from all over the world and working in different genres. A holder of two master’s degrees, the most recent one being in Magazine Journalism from Cardiff University, Nikita’s work has appeared in several publications such as Motor Sport Magazine, NME, Marriott Bonvoy, The Independent, and Metro. Her favorite tech includes the PS5, the DJI Air 3S, and her Google Pixel 7 Pro. She&#039;s also a licensed drone pilot and instant cameras expert so you&#039;ll find her testing these almost every week.&lt;/p&gt;&lt;p&gt;In her downtime, Nikita can usually be found sinking hours into RPGs on her PS5, flying a drone, out on a walk with a camera in hand, at a concert, watching F1, or planning her next tattoo. You can follow her photography account on Instagram&lt;a href=&quot;https://www.instagram.com/photos.bynikita/&quot; target=&quot;_blank&quot; rel=&quot;nofollow&quot;&gt; here&lt;/a&gt;.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/fvueVyQYtXYk4bq2B6HHuG-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[A black and brass Marshall Bromley 750 party speaker]]></media:description>                                                            <media:text><![CDATA[A black and brass Marshall Bromley 750 party speaker]]></media:text>
                                <media:title type="plain"><![CDATA[A black and brass Marshall Bromley 750 party speaker]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/fvueVyQYtXYk4bq2B6HHuG-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I've loved music for as long as I can remember. When I was 10 years old, I told my parents I wanted to learn the guitar — and learn the guitar I did. I wanted to be like Billie Joe Armstrong.</p><p>But I am, by no means, a pro guitarist, and I play very casually for myself (although I did used to play in my high school band). I play the bass too, and owning a bass means I need an amplifier because there's no way to use it without one. But I've always wished I had an amp and high-quality speaker all in one so that I could listen to my favorite tunes when I wasn't playing the guitar — and looks like that wish has come true in the form of the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">Marshall Bromley 750</a>.</p><div class="product"><a data-dimension112="f805ee85-dd71-4c3c-b3a2-01baa01452fe" data-action="Deal Block" data-label="Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with." data-dimension48="Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with." data-dimension25="$1299" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1294px;"><p class="vanilla-image-block" style="padding-top:115.92%;"><img id="5VnWQZR5GSzbp9Xz2zLhd9" name="bromley-750-deal" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/5VnWQZR5GSzbp9Xz2zLhd9.jpg" mos="" align="middle" fullscreen="" width="1294" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with.<a class="view-deal button" href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow" data-dimension112="f805ee85-dd71-4c3c-b3a2-01baa01452fe" data-action="Deal Block" data-label="Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with." data-dimension48="Thanks to a plethora of wired and wireless connectivity options, this party speaker doubles (or triples) as a guitar amp and a karaoke machine, while delivering powerful sound quality when you’re listening to music. A massive 500W power output makes the bass sound loud and refined, while vocals are crystal clear. Sporting Marshall’s trademark premium design and build quality, the Bromley 750 is a force to be reckoned with." data-dimension25="$1299">View Deal</a></p></div><p>The Bromley 750 is Marshall's first-ever party speaker, and when I listened to it for the first time, all I could think to myself was, "Boy, what a debut." With more wired and wireless connectivity options than you could ask for, long battery life, an immersive lighting system, and almighty bass, it doesn't give you much to complain about. But that's not even the best part: it doubles as a guitar amp... as well as a karaoke machine! It's the speaker I've been waiting for.</p><h2 id="rock-n-roll-mesmerizing-design">Rock 'n' roll, mesmerizing design</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="3CYoYoEcxdUdh2cJwmrusH" name="Marshall_Bromley750_ 7.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/3CYoYoEcxdUdh2cJwmrusH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>As someone who reviews tech for a living and has tested her fair share of audio gear, I have come across every type of speaker: the good, the bad, and the ugly. The Marshall Bromley 750 belongs to a secret fourth category: the outstanding. I've been a fan of Marshall's styling for a long time, and I've always found the British company's historic guitar amps simply beautiful, and the Bromley 750 borrows the same, classic, premium styling.</p><p>The Bromley 750 looks more like a guitar amp than a speaker, with its body and dials sporting a black and brass matte finish, and it looks downright stunning. The grilles that cover the front, top, side and rear woofers and tweeters are well built, and the golden Marshall branding looks great.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="hUxRSip2KhXanxUkyBmUuH" name="Marshall_Bromley750_ 11.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/hUxRSip2KhXanxUkyBmUuH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><div><blockquote><p>I have come across every type of speaker: the good, the bad, and the ugly. The Marshall Bromley 750 belongs to a secret fourth category: the outstanding.</p></blockquote></div><p>What I love most about the Bromley 750, though, is the integrated stage lighting located behind the front grille. It's customizable (three modes) via the button above the grille, and one of the modes makes the lighting react to the music you're playing. Not only does it work well and makes you feel like you're at a gig, but it's also classy and not garish, like RGB lighting on some speakers.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="FJteM8nSWGVqXfr47xN3MH" name="Marshall_Bromley750_ 8.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/FJteM8nSWGVqXfr47xN3MH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I use the <a href="https://www.tomsguide.com/audio/headphones/marshall-monitor-iii-review">Marshall Monitor III ANC</a> headphones every day, and one thing I love about the cans' design is the clickable control dial which resembles an electric guitar's input jack. The Bromley 750 shares a similar design philosophy: every button and dial resembles something you'd find on either a guitar or an amplifier. It's oh-so-satisfying to turn the dials or feel the lovely tactile feedback when pressing its buttons.</p><h2 id="and-it-sounds-even-better-than-it-looks">And it sounds even better than it looks</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="SuhdumUJmhG7JFdNc4LsEH" name="Marshall_Bromley750_ 1.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/SuhdumUJmhG7JFdNc4LsEH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I could wax poetic about the Marshall Bromley 750's design but then we'd be here for days, so I'll talk about something that's <em>even </em>better than its looks: the sound quality. I don't say this often, but the Bromley 750's sound profile is flawless, so much so that I was <em>actively</em> looking for flaws and yet, I found none.</p><p>The Bromley 750's sound profile and equalizer are customizable via the bass, treble and Sound Character (Dynamic to Loud) dials, so you can tailor it to your listening style. When the Sound Character dial is turned all the way up to Loud and the volume is at its highest, the speaker gets <em>very </em>loud, making it perfect for gatherings and DJ sets. It sounds fantastic outdoors as well as indoors, as I tested it in both environments.</p><p>With its 500W power output, the bass sounds meaty yet not booming, and mids and highs sound well-balanced, while True Stereophonic 360° sound ensures you hear the same audio regardless of the listening angle. I truly appreciated hearing every note Roger Waters plucked on his bass in Pink Floyd's 'Money,' and being able to hear the slot machines going off at the beginning of the track around me felt extremely immersive.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="TSkwyAQg3cgoL5w46hKqsH" name="Marshall_Bromley750_ 10.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/TSkwyAQg3cgoL5w46hKqsH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Even though the bass is loud and powerful, it doesn't overpower other instruments or vocals. For instance, in 'Up From the Bottom' by Linkin Park, which is a nu-metal track with guitar riffs and heavy drums, all the instruments as well as Emily Armstrong's vocals sounded melodious. The Bromley 750 is perfect for thumping electropop too, so fans of the likes of Charli xcx, Daft Punk and Chvrches will be pleased with its performance.</p><p>Being able to change the Sound Character on a scale of Dynamic and Loud is advantageous too. Turn the dial to Dynamic and you get refined, detailed vocals with plenty of fidelity (in the absence of LDAC or aptX support). Go to the opposite end of the spectrum and you've got solid low-end impact that shakes the floor.</p><h2 id="a-multi-purpose-versatile-beast">A multi-purpose, versatile beast</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="b69nAtuE2GyrtpahGbUaQH" name="Marshall_Bromley750_ 4.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/b69nAtuE2GyrtpahGbUaQH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Marshall Bromley 750 isn't like any ol' regular speaker. It's a party speaker, after all, and its wide array of connectivity options will keep everyone satisfied. In terms of wireless connectivity, you get Bluetooth 5.3 with SBC, AAC and LC3 codec support, as well as multipoint connectivity. Wired connectivity is even better with a 3.5mm aux port and USB-C for wired playback, two XLR/6.35mm combo ports for microphones and acoustic/electric guitars, and RCA ports for keyboards and turntables.</p><p>Yes, because you can connect a microphone to the Bromley 750, this means you can use it as a karaoke machine. As a karaoke enthusiast, I love this feature, and I also love that there's a reverb/delay dial above the speaker's front grille, enabling you to add effects to not just karaoke performances, but to your instruments too.</p><p>I plugged an electric guitar into the Bromley 750 and spent some time noodling on it, and it worked exactly like an amp does. There's plenty to like about Marshall's debut speaker, and for musicians and mobile DJs, I'm finding it hard to fault.</p><h2 id="the-elephant-s-in-the-room">The elephant(s) in the room...</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="JGfTaRRUkJCXGxxEJ8SJtH" name="Marshall_Bromley750_ 6.JPG" alt="A black and brass Marshall Bromley 750 party speaker" src="https://cdn.mos.cms.futurecdn.net/JGfTaRRUkJCXGxxEJ8SJtH.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>Sure, the Marshall Bromley 750 is great. I'd even say that it's near-perfect. <em>Near. </em>That's down to two reasons: lack of traditional stereo-speaker support, and the steep, steep price. The lack of stereo-speaker support means you can't synchronize two Bromley 750s together, which feels like a missed opportunity to me — especially because it's meant to be used to soundtrack parties and DJ sets.</p><p>I can get over it, that's fine, but perhaps the second point is even harder to digest. The Bromley 750 costs a lot, retailing for <a href="https://www.amazon.com/Marshall-Bromley-Portable-Wireless-Speaker/dp/B0FTZXFVJ1/" target="_blank" rel="nofollow">$1,299</a> / <a href="https://www.argos.co.uk/product/7767133/" target="_blank" rel="nofollow">£899</a>, making it the most expensive speaker I've tested (so far). It isn't for the faint of heart, but if you can afford it, I really can't think of reasons not<em> </em>to buy it.</p><p>To paraphrase Joey Tribbiani: The design? Good. The features? Good. The battery life? Good. The sound quality? <em>Gooooood.</em></p><div style="min-height: 250px;">                                <div class="kwizly-quiz kwizly-O6V9nO"></div>                            </div>                            <script src="https://kwizly.com/embed/O6V9nO.js" async></script><h3 class="article-body__section" id="section-more-from-tom-s-guide"><span>More from Tom's Guide</span></h3><ul><li><a href="https://www.tomsguide.com/audio/bluetooth-speakers/marshall-bromley-750-review">I just tested Marshall’s first party speaker — and it’s perfect for audiophiles, musicians and even karaoke enthusiasts</a></li><li><a href="https://www.tomsguide.com/us/best-bluetooth-speakers,review-1982.html">Best Bluetooth speakers in 2025</a></li><li><a href="https://www.tomsguide.com/audio/i-ditched-my-smartphone-to-listen-to-music-on-my-decade-old-ipod-here-are-3-things-i-liked-and-2-i-didnt">I ditched my smartphone to listen to music on my decade-old iPod — 3 things I liked and 2 I didn't</a></li></ul>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ I put these 2 Bluetooth speakers to the test that can go anywhere — here's my top pick under $50  ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/i-put-jlab-and-tribits-budget-bluetooth-speakers-to-the-test-and-heres-why-you-need-to-spend-that-extra-usd10</link>
                                                                            <description>
                            <![CDATA[ We love finding budget products, but sometimes a small upgrade is needed. ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">qR8shCWK6vR63ex5PEgRdd</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/8DyNYrALG7dRgYgsuEhSij-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Sat, 20 Dec 2025 06:30:00 +0000</pubDate>                                                                                                                                <updated>Sat, 20 Dec 2025 22:55:06 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money.She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK online, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews.She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health, and has her own newsletter where she shares reviews of her favorite books, Ashley’s Reading Nook. In previously published work, she has reviewed live music events, books, and wellness products.She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best.In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest fantasy novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/8DyNYrALG7dRgYgsuEhSij-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JLab Pop Party photographed on a blue background next to a Tribit PocketGo photographed ona. blue background.]]></media:description>                                                            <media:text><![CDATA[JLab Pop Party photographed on a blue background next to a Tribit PocketGo photographed ona. blue background.]]></media:text>
                                <media:title type="plain"><![CDATA[JLab Pop Party photographed on a blue background next to a Tribit PocketGo photographed ona. blue background.]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/8DyNYrALG7dRgYgsuEhSij-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>I’ve tested my fair share of audio gear here at Tom’s Guide, and there’s no denying that sometimes, budget stuff just doesn’t hit the mark. And while I love looking for budget gear that can save you some cash, sometimes it’s worth spending that extra bit of money to make the step up.</p><p>I’ve recently tested two budget portable Bluetooth speakers: The <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-pop-party-review">JLab Pop Party</a> and the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo</a>, and they proved this point perfectly. </p><p>The <a href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker/dp/B0F39TVYSP" target="_blank" rel="nofollow">JLab Pop Party is available at Amazon for $24</a>, and the <a href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Floatable/dp/B0FQJR6RTS" target="_blank" rel="nofollow">Tribit PocketGo is available for $34</a>, so both of these speakers are super affordable, but for the sake of $10, I know which one I’m buying. </p><div class="product"><a data-dimension112="d2841b13-a9cf-49c5-ae17-911c034e6dcd" data-action="Deal Block" data-label="The JLab Pop Party speaker offers affordability, portability and fun RGB lighting that can be controlled through the companion app. But there are some compromises made to the sound performance to keep that price tag low. It’s cheap and cheerful, but you should definitely weigh up your options first." data-dimension48="The JLab Pop Party speaker offers affordability, portability and fun RGB lighting that can be controlled through the companion app. But there are some compromises made to the sound performance to keep that price tag low. It’s cheap and cheerful, but you should definitely weigh up your options first." data-dimension25="$24" href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker/dp/B0F39TVYSP" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:805px;"><p class="vanilla-image-block" style="padding-top:186.34%;"><img id="qskSAB9tVD6rSsifFPkhw4" name="jlab-pop-party-portable-bluetooth-speake-bec2e41d-5c99-46d0-be49-960aef6a8b2a.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/qskSAB9tVD6rSsifFPkhw4.jpg" mos="" align="middle" fullscreen="" width="805" height="1500" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>The JLab Pop Party speaker offers affordability, portability and fun RGB lighting that can be controlled through the companion app. But there are some compromises made to the sound performance to keep that price tag low. It’s cheap and cheerful, but you should definitely weigh up your options first.<a class="view-deal button" href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker/dp/B0F39TVYSP" target="_blank" rel="nofollow" data-dimension112="d2841b13-a9cf-49c5-ae17-911c034e6dcd" data-action="Deal Block" data-label="The JLab Pop Party speaker offers affordability, portability and fun RGB lighting that can be controlled through the companion app. But there are some compromises made to the sound performance to keep that price tag low. It’s cheap and cheerful, but you should definitely weigh up your options first." data-dimension48="The JLab Pop Party speaker offers affordability, portability and fun RGB lighting that can be controlled through the companion app. But there are some compromises made to the sound performance to keep that price tag low. It’s cheap and cheerful, but you should definitely weigh up your options first." data-dimension25="$24">View Deal</a></p></div><div class="product"><a data-dimension112="741284bb-8ea1-4096-9c2a-272d56451c03" data-action="Deal Block" data-label="For less than $35, the Tribit PocketGo packs one heck of a punch in the sound department and is the ultimate rugged speaker. It has a waterproof rating of IP68 and military-grade drop protection, making it the perfect companion on hikes. With some very minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension48="For less than $35, the Tribit PocketGo packs one heck of a punch in the sound department and is the ultimate rugged speaker. It has a waterproof rating of IP68 and military-grade drop protection, making it the perfect companion on hikes. With some very minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension25="$34" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Floatable/dp/B0FQJR6RTS" target="_blank" rel="nofollow"><figure class="van-image-figure "  ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1382px;"><p class="vanilla-image-block" style="padding-top:77.13%;"><img id="TGnyjV6K4gd24LvZQHn5t4" name="tribit-pocketgo-portable-bluetooth-speak-5602c826-7922-4b25-b1fe-90cc0726f169.jpg" caption="" alt="" src="https://cdn.mos.cms.futurecdn.net/TGnyjV6K4gd24LvZQHn5t4.jpg" mos="" align="middle" fullscreen="" width="1382" height="1066" attribution="" endorsement="" credit="" class=""></p></div></div></figure></a><p>For less than $35, the Tribit PocketGo packs one heck of a punch in the sound department and is the ultimate rugged speaker. It has a waterproof rating of IP68 and military-grade drop protection, making it the perfect companion on hikes. With some very minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker.<a class="view-deal button" href="https://www.amazon.com/Tribit-Bluetooth-Waterproof-Dustproof-Floatable/dp/B0FQJR6RTS" target="_blank" rel="nofollow" data-dimension112="741284bb-8ea1-4096-9c2a-272d56451c03" data-action="Deal Block" data-label="For less than $35, the Tribit PocketGo packs one heck of a punch in the sound department and is the ultimate rugged speaker. It has a waterproof rating of IP68 and military-grade drop protection, making it the perfect companion on hikes. With some very minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension48="For less than $35, the Tribit PocketGo packs one heck of a punch in the sound department and is the ultimate rugged speaker. It has a waterproof rating of IP68 and military-grade drop protection, making it the perfect companion on hikes. With some very minor EQ adjustments in the Tribit app, this has quickly become my most-used speaker." data-dimension25="$34">View Deal</a></p></div><h2 id="go-rugged">Go rugged</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="BzZgxLUemS3J7E73zpJd3a" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/BzZgxLUemS3J7E73zpJd3a.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>One of the best things about having a tiny speaker that isn’t too heavy is that you can take it with you absolutely anywhere. I’ve taken portable speakers with me on countless adventures up mountains and on muddy trails, and sometimes the weather doesn't exactly play ball. </p><p>If you find yourself caught in a rainstorm or strong winds, you’re going to want something that can withstand whatever is thrown at it. The JLab Pop Party has a waterproof rating of IP55, so it will be protected from water splashes in all directions, but you may need more than that. </p><p>The Tribit PocketGo, on the other hand, has a waterproof rating of IP68, meaning it can actually be submerged underwater and come out unscathed. It’s also been drop tested to a military standard and can withstand drops up to four feet. So for $10 extra, you’re coming away with more assurance that the speaker will withstand your adventure. </p><h2 id="a-light-show-or-longer-listening">A light show or longer listening</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="iCYWDUgYaN5K2JhckriLmD" name="JLab Pop Party" alt="JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/iCYWDUgYaN5K2JhckriLmD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>JLab is well-known for the party features that come with their speakers. The RGB lighting offers a fun way to make your listening immersive as it flashes to the beat of the song, or a great way to stay visible if it’s dark. But this lighting comes at a cost. </p><p>The Pop Party has eight hours of battery life (which isn’t great), but this is pretty much helved when the RGB lights are on. And you can’t do much with four hours of battery life. If you’re listening at more than 50% volume, that playtime will reduce even further.</p><p>The PocketGo offers 20 hours of battery life, and the sound is extremely loud, too. At full volume, this speaker can fill my whole house with music, which is nice considering it fits in the palm of my hand. </p><h2 id="sound-quality">Sound quality</h2><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="ryja4TD89MLWDNspHawtiZ" name="The Tribit PocketGo is the speaker that I will now be bringing with me everywhere, from picnics to hikes. It has awesome sound and can get super loud despite being compact and lightweight. It offers 20 hours of battery life, even with the incredibly loud volumes.  My only qualm with the speaker is that it requires some EQ alterations in the app, depending on the genre you’re listening to. But when it can offer a waterproof rating of IP68 and military-grade drop protection at such a low price, I can’t deny that this is the ultimate adventure speaker." alt="The Tribit PocketGo speaker in black photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/ryja4TD89MLWDNspHawtiZ.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The Tribit speaker offers well-balanced sound that I could quite literally listen to all day long. </p><p>The JLab speaker, on the other hand, was tinny and suffered from frequency masking, making the vocals indiscernible from other instruments in the tracks I was listening to. This was pretty frustrating as someone who loves to listen to every layer of the song and really take in the production. </p><p>So, for $10 extra, you’re getting the assurance of better quality, bigger sound, and longer battery life. The choice is clear to me — splash that extra cash. If you want to find out more about the speakers, you can read our full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-pop-party-review">JLab Pop Party review</a> and the full <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review">Tribit PocketGo review</a>.</p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
                                <item>
                                                            <title><![CDATA[ The JLab Pop Party is the cheapest speaker I’ve ever tested — but at what cost ]]></title>
                                                                                                                                                                                                <link>https://www.tomsguide.com/audio/bluetooth-speakers/jlab-pop-party-review</link>
                                                                            <description>
                            <![CDATA[ The JLab Pop Party Bluetooth speaker is affordable and portable, but are there too many compromises for the budget price tag? ]]>
                                                                                                            </description>
                                                                                                                                <guid isPermaLink="false">fzQDERwwY5DZzqeXJKRdqb</guid>
                                                                                                <enclosure url="https://cdn.mos.cms.futurecdn.net/fRYHXqQWTbXJB786JTZzpD-1280-80.jpg" type="image/jpeg" length="0"></enclosure>
                                                                        <pubDate>Wed, 17 Dec 2025 17:37:07 +0000</pubDate>                                                                                                                                <updated>Thu, 26 Mar 2026 10:31:21 +0000</updated>
                                                                                                                                            <category><![CDATA[Bluetooth Speakers]]></category>
                                                    <category><![CDATA[Audio]]></category>
                                                    <category><![CDATA[Speakers]]></category>
                                                                                                <author><![CDATA[ ashley.thieme@futurenet.com (Ashley Thieme) ]]></author>                    <dc:creator><![CDATA[ Ashley Thieme ]]></dc:creator>                                                                                    <dc:source><![CDATA[ https://cdn.mos.cms.futurecdn.net/3AWovHjApwuNrSGRS6WBcL.jpg ]]></dc:source>
                                                                <dc:description><![CDATA[ &lt;p&gt;Ashley Thieme is a staff writer on the Reviews team at Tom’s Guide where she tests out the latest tech so you can know what’s going to be worth your time and money. She has a master’s degree in Magazine Journalism and a bachelor’s degree in Journalism, Media and Sociology from Cardiff University. She has bylines in titles including Women’s Health UK, sharing the latest health and wellness news stories, and Virgin Radio UK, providing the latest entertainment news and working on celebrity interviews. She has experience reporting on a variety of topics including music, literature, motorsport, entertainment and health. In previously published work, she has reviewed live music events, books, and wellness products. She values the importance of tech enhancing your life rather than taking over, and as a music fanatic, she is always looking for the best way to listen to new music releases. Discovering the top audio equipment that enhances sound quality and provides optimum comfort is what Ashley does best. In her spare time, Ashley enjoys hitting her reading goals on Goodreads by getting into the latest novels with a cup of tea as well as getting out in the Welsh mountains for a good hike on the weekend.&lt;/p&gt; ]]></dc:description>
                                                                                                                                <cf:isSponsored>false</cf:isSponsored>
                <cf:hasAffiliateLinks>false</cf:hasAffiliateLinks>
                <cf:isPaid>false</cf:isPaid>
                                                                                                                                <media:content type="image/jpeg" url="https://cdn.mos.cms.futurecdn.net/fRYHXqQWTbXJB786JTZzpD-1280-80.jpg">
                                                            <media:credit><![CDATA[Tom&#039;s Guide]]></media:credit>
                                                                                                                                                                                                                                    <media:description><![CDATA[JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background. ]]></media:description>                                                            <media:text><![CDATA[JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background. ]]></media:text>
                                <media:title type="plain"><![CDATA[JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background. ]]></media:title>
                                                    </media:content>
                                                    <media:thumbnail url="https://cdn.mos.cms.futurecdn.net/fRYHXqQWTbXJB786JTZzpD-1280-80.jpg" />
                                                                                                                                                                    <content:encoded >
                            <![CDATA[
                            <article>
                                <p>The JLab Pop Party Bluetooth speaker is an affordable, portable option for anyone who wants to take their music on the go. It features an easy-to-use companion app and cool RGB lighting. </p><p>However, that lighting is what holds it back from being amongst the <a href="https://www.tomsguide.com/us/best-bluetooth-speakers">best Bluetooth speakers</a>. The LEDs reduce the Pop Party’s battery life to just 4-5 hours, which is further decreased if you listen at high volumes. On top of that, the single button is finicky and frustrating, which forced me to control the speaker using my phone.</p><p>On top of all that, the sound quality is fairly poor, making this a difficult speaker to recommend. If you want to find out more about how I got on with this speaker, you can keep reading this full JLab Pop Party review. </p><h2 class="article-body__section" id="section-jlab-pop-party-review-specs"><span>JLab Pop Party review: Specs</span></h2><div ><table><tbody><tr><td class="firstcol " ><p><strong>Price</strong></p></td><td  ><p><a href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker/dp/B0F39TVYSP" target="_blank" rel="nofollow">$24</a>/<a href="https://www.amazon.co.uk/JLab-Ultra-Portable-Bluetooth-Speaker-Playtime/dp/B0F39TVYSP" target="_blank" rel="nofollow">£24</a></p></td></tr><tr><td class="firstcol " ><p><strong>Dimensions</strong></p></td><td  ><p>7.55 x 3.11 x 1.89 inches</p></td></tr><tr><td class="firstcol " ><p><strong>Weight</strong></p></td><td  ><p>8.7 ounces</p></td></tr><tr><td class="firstcol " ><p><strong>Battery life</strong></p></td><td  ><p>8 hours</p></td></tr><tr><td class="firstcol " ><p><strong>Connectivity</strong></p></td><td  ><p>Bluetooth 5.3</p></td></tr><tr><td class="firstcol " ><p><strong>Codec support</strong></p></td><td  ><p>SBC, AAC</p></td></tr><tr><td class="firstcol " ><p><strong>App support</strong></p></td><td  ><p>Yes</p></td></tr><tr><td class="firstcol " ><p><strong>Lighting</strong></p></td><td  ><p>RBG, 6 patterns</p></td></tr><tr><td class="firstcol " ><p><strong>Waterproofing</strong></p></td><td  ><p>IP55</p></td></tr><tr><td class="firstcol " ><p><strong>Accessories</strong></p></td><td  ><p>2ft. USB-C lead</p></td></tr></tbody></table></div><h2 class="article-body__section" id="section-jlab-pop-party-review-price-availability"><span>JLab Pop Party review: Price & availability</span></h2><p>The JLab Pop Party speaker is available for purchase for <a href="https://www.amazon.com/JLab-Party-Portable-Bluetooth-Speaker/dp/B0F39TVYSP" target="_blank" rel="nofollow">$24</a> / <a href="https://www.amazon.co.uk/JLab-Ultra-Portable-Bluetooth-Speaker-Playtime/dp/B0F39TVYSP" target="_blank" rel="nofollow">£24</a> at Amazon. This price tag makes it one of the cheapest options available, and the cheapest speaker I have ever tested. </p><p>While this is a low price, I have to admit that after listening to the speaker, it’s about right. I certainly wouldn’t pay more for a speaker that sounds like this.</p><p>For just $5 more, you could pick up the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tozo-pe1-review">Tozo PE1</a> ($29), which packs way more of a punch in the volume department. Or for an extra $10, you can pick up (my personal favorite) the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/tribit-pocketgo-review#section-tribit-pocketgo-review-specs">Tribit PocketGo</a> ($34), which has awesome sound profile settings and, as the name would suggest, fits right into your pocket. But the JLab Pop Party offers more battery life (with RGB lights off) than the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jbl-go-4-review">JBL Go 4</a>, which has a battery life of just seven hours.</p><h2 class="article-body__section" id="section-jlab-pop-party-review-design-controls"><span>JLab Pop Party review: Design & controls</span></h2><ul><li><strong>Compact size</strong></li><li><strong>Loop handle</strong></li><li><strong>Only one control button </strong></li></ul><p>The JLab Pop Party is a portable speaker with RGB lighting. With the lighting on, it’s a pretty funky speaker, but with them off, it looks pretty cheap (which it is at $24) and ugly. An oval mesh covers the front of the speaker, which is surrounded by the lighting around the edges. </p><p>It measures 7.6 x 3.1 x 1.9 inches, so it’s extremely compact and as portable as the Tribit PocketGo (4.2 x 3.1 x 1.6 inches). The Pop Party weighs 8.7 ounces, which is pretty heavy compared to the 7.8-ounce Tribit PocketGo, which feels much lighter when carrying it around. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="2kWJa5hnKKbHsDM7VDFFbD" name="JLab Pop Party" alt="JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/2kWJa5hnKKbHsDM7VDFFbD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>You can control the speaker with one multifunctional button. This button turns the speaker on and off with a long press, but if you want to be able to control volume and skip songs with it, you have to button mash. You can change these controls in the JLab app, but it becomes laborious. </p><p>The Pop Party speaker can be attached to virtually anything thanks to its loop handle. I was able to easily attach it around the strap of my bag, so it was easy to carry around. This design is similar to the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/ue-miniroll-review-tiny-but-mighty#section-ue-miniroll-review">Ultimate Ears Miniroll</a> ($79), and is a great feature for smaller speakers like this.</p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="RQ6X6ZFe6PupYzJfV7ECkD" name="JLab Pop Party" alt="JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/RQ6X6ZFe6PupYzJfV7ECkD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>The loop handle makes it ideal for taking on outdoor adventures, but you may want something a little more rugged to withstand harsher conditions. The Pop Party has a waterproof rating of IP55, which means it’s protected from water splashes in all directions.</p><p>If you’re in the market for a virtually indestructible speaker, I would recommend the Tribit PocketGo, which has a waterproof rating of IP68, or the Tozo PE1, which has a waterproof rating of IPX8. Both of these speakers can even go in the shower with you and come out unscathed (at least in the short term — as steam and soaps can break down the internal waterproofing of IP-rated products).</p><h2 class="article-body__section" id="section-jlab-pop-party-review-connectivity-app"><span>JLab Pop Party review: Connectivity & app</span></h2><ul><li><strong>Bluetooth</strong></li><li><strong>No multipoint connectivity</strong></li><li><strong>JLab app is easy to use</strong></li></ul><p>The JLab Pop Party speaker uses Bluetooth 5.3 to stream music over SBC and AAC audio codecs. It was easy to connect to my phone, but there’s no multipoint connectivity, so to switch devices, I had to fully disconnect and reconnect every time. </p><p>Like the JLab Go Party, the Pop Party is ‘LabSync Stereo Pairing’ compatible. LabSync allows up to 100 JLab speakers to be connected in stereo, creating bigger sound. This can be used with any JLab speaker; they don’t need to be the same model. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="qKKNw5oBFCN6RDohGj46AA" name="JLab app screenshots" alt="Screenshots from the JLab app taken when testing the JLab Pop Party Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/qKKNw5oBFCN6RDohGj46AA.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable"><a href='https://cdn.mos.cms.futurecdn.net/qKKNw5oBFCN6RDohGj46AA.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JLab)</span></figcaption></figure><p>The JLab app provides a lot of opportunities for customization. You can adjust the single control button, EQ settings, and the RGB lighting. </p><h2 class="article-body__section" id="section-jlab-pop-party-review-sound-quality"><span>JLab Pop Party review: Sound quality</span></h2><ul><li><strong>Doesn’t get very loud</strong></li><li><strong>Poor audio quality</strong></li><li><strong>Frequency masking</strong></li></ul><p>If you’re looking for a powerful speaker to fill a room with sound, the JLab Pop Party is not the one. But if you want a cheap speaker to play music <em>very</em> casually with some fun lights, then it’s fine. It’s not going to blow anyone away with Hi-Fi audio, but it is $24 after all. </p><p>Firstly, I listened to <a href="https://open.qobuz.com/track/33382287">‘Blue Monday’ by New Order</a> to test out electronic genres. I initially listened to this with the default JLab signature EQ setting and was disappointed by how flat it sounded, so I headed to the JLab app to attempt to salvage the sound. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1510px;"><p class="vanilla-image-block" style="padding-top:56.29%;"><img id="HQysrFxycsknHmqjm2X4AA" name="JLab app screenshots" alt="Screenshots from the JLab app taken when testing the JLab Pop Party Bluetooth speaker" src="https://cdn.mos.cms.futurecdn.net/HQysrFxycsknHmqjm2X4AA.jpg" mos="" align="middle" fullscreen="1" width="1510" height="850" attribution="" endorsement="" class="inline expandable"><a href='https://cdn.mos.cms.futurecdn.net/HQysrFxycsknHmqjm2X4AA.jpg' target='_blank' class='expand-button icon-expand-image icon' ></a></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: JLab)</span></figcaption></figure><p>I tried the bass boost setting, but it made the song sound incredibly tinny. This is a shame because this song would be perfect for showcasing bass capabilities. I ended up creating a custom EQ setting for this song in a V-shape, using increased bass, lower mids and increased highs. If you're ever in doubt, this is a great way to adjust your sound profile. </p><p>Many other audio brands, such as Skullcandy and Beats, use this V-shape EQ setting to achieve the most pleasing sound for a wide range of consumers. This worked really well for me and made the song sound more full-bodied, but the sound still wasn’t as good as when I listened on the Tribit PocketGo. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="PHyhmbCkoP6pttuqJrcAuD" name="JLab Pop Party" alt="JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/PHyhmbCkoP6pttuqJrcAuD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>I then listened to <a href="https://open.qobuz.com/track/341749112">‘Goodnight’ by Florence Road</a> with the “Balanced” EQ preset, and, again, it sounded extremely tinny. ‘Goodnight’ usually sounds very clear thanks to its well-mixed soundscape, but the Pop Party struggled to replicate this. The speaker couldn’t discern between the high-frequency vocals and lead guitar, which resulted in a confused sound. </p><p>Finally, I listened to <a href="https://open.qobuz.com/track/339606226">‘I CARE’ by Turnstile</a>, which is a melodic alt-rock song, using the JLab “Signature” preset. For this song, the preset worked pretty well. However, the same issue occurred with confusion of the vocals, but this time with the drums. It’s as if the two were becoming one sound, and this frequency masking became really annoying. But the rest of the song sounded good, especially during the softer, more melodic parts.</p><iframe allow="" height="390" width="378" id="" style="" class="position-center" data-lazy-priority="low" data-lazy-src="https://widget.qobuz.com/playlist/49519474?zone=GB-en"></iframe><h2 class="article-body__section" id="section-jlab-pop-party-review-battery-life"><span>JLab Pop Party review: Battery life</span></h2><ul><li><strong>Short battery life</strong></li><li><strong>RGB lighting makes battery life even shorter</strong></li><li><strong>Takes 3 hours to fully charge</strong></li></ul><p>The first thing I noticed about the JLab Pop Party speaker is that I wasn’t getting anywhere near the advertised 8+ hours of battery. The speaker had just 50% battery left after two hours of listening, so I was a little confused. </p><p>After doing some digging, I discovered that the 8+ hours of battery life are only applicable if you’re using the speaker without the RGB lighting. With the lighting turned on, you get just 4-5 hours of listening time. </p><figure class="van-image-figure  inline-layout" data-bordeaux-image-check ><div class='image-full-width-wrapper'><div class='image-widthsetter' style="max-width:1920px;"><p class="vanilla-image-block" style="padding-top:56.25%;"><img id="Py8g3pqZGYfW8VHamYatpD" name="JLab Pop Party" alt="JLab Pop Party portable Bluetooth speaker with RGB lighting photographed on a blue background." src="https://cdn.mos.cms.futurecdn.net/Py8g3pqZGYfW8VHamYatpD.jpg" mos="" align="middle" fullscreen="" width="1920" height="1080" attribution="" endorsement="" class="inline"></p></div></div><figcaption itemprop="caption description" class=" inline-layout"><span class="credit" itemprop="copyrightHolder">(Image credit: Tom's Guide)</span></figcaption></figure><p>This obviously isn’t great because one of the only draws of this speaker is its funky lighting. If you want flashy lights and better battery life, I’d recommend the <a href="https://www.tomsguide.com/audio/bluetooth-speakers/jlab-go-party-review">JLab Party Go</a> ($34), which lasts eight hours with its lights. But if you aren’t fussed about lights and want something practical and just as small as the Pop Party, I would recommend the Tribit PocketGo with its 20 hours of battery life. </p><p>To make matters worse, after your puny four hours of listening time, the Pop Party takes three hours to recharge via USB-C. This is a long time considering how little playtime you actually get.</p><h2 class="article-body__section" id="section-jlab-pop-party-review-verdict"><span>JLab Pop Party review: Verdict</span></h2><p>The JLab Pop Party speaker is an affordable and compact option that looks cool thanks to its funky RGB lighting. Thanks to its user-friendly companion app, you can customize tons of settings. Which works out well, as you’ll need to adjust the EQ to get decent sound. </p><p>However, JLab has clearly cut some corners in trying to keep the price low. While it’s the cheapest speaker I’ve tested, you can <em>really</em> tell. The audio quality is poor, with tinny sound in most places and frequency masking that muddies songs. The short battery life also lets this speaker down, and, to top it all off, the single control button means you rely on your phone for any changes you need to make, including volume and skipping songs.</p><p>If you want a super-portable speaker for as cheap as possible, you might want to give it a try. But everyone else? It’s skippable. </p>
                                                            </article>
                            ]]>
                        </content:encoded>
                                                </item>
            </channel>
</rss>