diff --git a/gui/components/Preferences.qml b/gui/components/Preferences.qml
index 106af7af6f00cd30add38933dcd1bf12fa3e1a5c..f205358eb53f11e47c23ecd6776af59836ec268d 100644
--- a/gui/components/Preferences.qml
+++ b/gui/components/Preferences.qml
@@ -5,10 +5,6 @@ import QtQuick.Controls.Material 2.1
 
 import "../themes/themes.js" as Theme
 
-// TODO
-// [ ] disable UDP if provider doesn't support it
-// [ ] disable UDP if the platform doesn't support it
-
 ThemedPage {
     title: qsTr("Preferences")
 
@@ -116,7 +112,7 @@ ThemedPage {
             }
 
             Label {
-                text: qsTr("UDP can make the VPN faster")
+                text: qsTr("UDP can make the VPN faster, but it might be blocked on certain networks")
                 width: parent.width
                 color: "gray"
                 visible: true
@@ -124,6 +120,7 @@ ThemedPage {
                 font.pixelSize: Theme.fontSize - 3
                 Layout.leftMargin: 10
                 Layout.rightMargin: 10
+                Layout.preferredWidth: 240
             }
 
             MaterialCheckBox {
@@ -232,5 +229,8 @@ ThemedPage {
         if (ctx && ctx.udp == "true") {
             useUDP.checked = true
         }
+        if (ctx && ctx.offersUdp == "false") {
+            useUDP.enabled = false
+        }
     }
 }
diff --git a/pkg/backend/README.md b/pkg/backend/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1adefe8fae6fbace0203bfd1b7a67bcd3f9089ba
--- /dev/null
+++ b/pkg/backend/README.md
@@ -0,0 +1,10 @@
+# how to add new fields to backend api
+
+1. add to the struct in `status.go`
+2. populate it in `toJson()` method.
+3. modify the `bitmask` interface in `pkg/bitmask/bitmask.go` (note: this is
+   a relict from the past, we can probably get rid of since there'll be
+   a single implementation in the foreseeable future).
+4. modify the `bitmask` struct in `pkg/vpn/main.go`
+5. modify the bitmask instantiation in `pkg/vpn/main.go:Init`
+6. implement functionality...
diff --git a/pkg/backend/status.go b/pkg/backend/status.go
index f21fdddd794984d495751a99266b45ea1e052d95..2ed5cfdd6148aa45ea5b02412fd5b7767f79ffcb 100644
--- a/pkg/backend/status.go
+++ b/pkg/backend/status.go
@@ -52,6 +52,7 @@ type connectionCtx struct {
 	BestLocation    string              `json:"bestLocation"`
 	Transport       string              `json:"transport"`
 	UseUDP          bool                `json:"udp"`
+	OffersUDP       bool                `json:"offersUdp"`
 	ManualLocation  bool                `json:"manualLocation"`
 	IsReady         bool                `json:"isReady"`
 	CanUpgrade      bool                `json:"canUpgrade"`
@@ -73,6 +74,7 @@ func (c *connectionCtx) toJson() ([]byte, error) {
 		c.BestLocation = c.bm.GetBestLocation(transport)
 		c.Transport = transport
 		c.UseUDP = c.cfg.UDP // TODO initialize bitmask too
+		c.OffersUDP = c.bm.OffersUDP()
 		c.ManualLocation = c.bm.IsManualLocation()
 		c.CanUpgrade = c.bm.CanUpgrade()
 		c.Motd = c.bm.GetMotd()
diff --git a/pkg/bitmask/bitmask.go b/pkg/bitmask/bitmask.go
index d02487b89533d8615c71e36eaa7563187588e3c5..80b502ed0a27c7f5dbec2b9826590a942bddd9c8 100644
--- a/pkg/bitmask/bitmask.go
+++ b/pkg/bitmask/bitmask.go
@@ -36,6 +36,7 @@ type Bitmask interface {
 	GetTransport() string
 	SetTransport(string) error
 	UseUDP(bool) error
+	OffersUDP() bool
 	GetCurrentGateway() string
 	GetCurrentLocation() string
 	GetCurrentCountry() string
diff --git a/pkg/vpn/bonafide/eip_service.go b/pkg/vpn/bonafide/eip_service.go
index 28d047973a79c98f9cb80dbf740b627958a2d5f4..1b8dc0184210b83ced59dc0a9cdbf20342a17ad9 100644
--- a/pkg/vpn/bonafide/eip_service.go
+++ b/pkg/vpn/bonafide/eip_service.go
@@ -76,6 +76,26 @@ func (b *Bonafide) setupAuthentication(i interface{}) {
 	}
 }
 
+func (b *Bonafide) IsUDPAvailable() bool {
+	if b.eip == nil {
+		return false
+	}
+	for _, gw := range b.eip.Gateways {
+		for _, t := range gw.Capabilities.Transport {
+			if t.Type == "openvpn" {
+				for _, proto := range t.Protocols {
+					if proto == "udp" {
+						return true
+					}
+				}
+			}
+
+		}
+
+	}
+	return false
+}
+
 func (b *Bonafide) fetchEipJSON() error {
 	eip3API := config.APIURL + "3/config/eip-service.json"
 	resp, err := b.client.Post(eip3API, "", nil)
diff --git a/pkg/vpn/main.go b/pkg/vpn/main.go
index 619a10f799e6ae51ae5a0242e320874785067c1b..176c86f7605b067a85816455ec148e8d9b5a1326 100644
--- a/pkg/vpn/main.go
+++ b/pkg/vpn/main.go
@@ -43,6 +43,7 @@ type Bitmask struct {
 	certPemPath      string
 	openvpnArgs      []string
 	udp              bool
+	offersUdp        bool
 	failed           bool
 	canUpgrade       bool
 	motd             []motd.Message
@@ -67,7 +68,7 @@ func Init() (*Bitmask, error) {
 		bonafide.Gateway{},
 		bonafide.Gateway{}, statusCh, nil, bf, launch,
 		"", nil, "", []string{},
-		false, false, false,
+		false, false, false, false,
 		[]motd.Message{}, ""}
 	// FIXME multiprovider: need to pass provider name early on
 	// XXX we want to block on these, but they can timeout if we're blocked.
@@ -150,6 +151,10 @@ func (b *Bitmask) UseUDP(udp bool) error {
 	return nil
 }
 
+func (b *Bitmask) OffersUDP() bool {
+	return b.bonafide.IsUDPAvailable()
+}
+
 func (b *Bitmask) GetMotd() string {
 	bytes, err := json.Marshal(b.motd)
 	if err != nil {