{"id":3327,"library":"zeroconf","title":"ZeroConf","description":"ZeroConf is a pure Python implementation of multicast DNS service discovery (mDNS/DNS-SD), commonly known as Bonjour or Apple's Zero Configuration Networking. It allows applications to discover services on a local network without manual configuration. The library is currently at version 0.148.0 and maintains an active release cadence with frequent bug fixes and feature updates.","status":"active","version":"0.148.0","language":"en","source_language":"en","source_url":"https://github.com/python-zeroconf/python-zeroconf","tags":["networking","discovery","mdns","zeroconf","service-discovery","bonjour"],"install":[{"cmd":"pip install zeroconf","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Required for detecting network interfaces.","package":"ifaddr","optional":false}],"imports":[{"symbol":"Zeroconf","correct":"from zeroconf import Zeroconf"},{"symbol":"ServiceInfo","correct":"from zeroconf import ServiceInfo"},{"symbol":"ServiceBrowser","correct":"from zeroconf import ServiceBrowser"},{"note":"Useful for defining a listener for service discovery events.","symbol":"ServiceStateChange","correct":"from zeroconf import ServiceStateChange"}],"quickstart":{"code":"import socket\nimport time\nfrom zeroconf import ServiceInfo, Zeroconf, ServiceBrowser\n\n# A simple listener for discovering services\nclass MyListener:\n    def add_service(self, zeroconf_instance, service_type, service_name):\n        info = zeroconf_instance.get_service_info(service_type, service_name)\n        if info:\n            print(f\"Service added: {service_name} at {info.server}, Port: {info.port}, Addr: {socket.inet_ntoa(info.addresses[0]) if info.addresses else 'N/A'}\")\n\n    def remove_service(self, zeroconf_instance, service_type, service_name):\n        print(f\"Service removed: {service_name}\")\n\n# --- Example Usage ---\nzeroconf = None\nbrowser = None\ninfo = None\ntry:\n    # 1. Register a service\n    desc = {'path': '/~example'}\n    ip_address = socket.gethostbyname(socket.gethostname()) # Or specify an explicit IP like \"127.0.0.1\"\n\n    info = ServiceInfo(\n        \"_http._tcp.local.\", # Service type\n        \"MyTestService._http._tcp.local.\", # Service name\n        addresses=[socket.inet_aton(ip_address)],\n        port=8080,\n        properties=desc,\n        server=\"example.local.\", # The server's hostname\n    )\n\n    zeroconf = Zeroconf()\n    print(f\"Registering service: {info.name} on {ip_address}:{info.port}\")\n    zeroconf.register_service(info)\n\n    # 2. Browse for services (will also find our own registered service)\n    print(\"Starting service browser for _http._tcp.local.\")\n    browser = ServiceBrowser(zeroconf, \"_http._tcp.local.\", listener=MyListener())\n\n    print(\"Running for 30 seconds to allow discovery and registration. Press Ctrl+C to stop.\")\n    time.sleep(30) # Keep running\nexcept KeyboardInterrupt:\n    print(\"Keyboard interrupt received. Shutting down.\")\nfinally:\n    if zeroconf:\n        print(\"Unregistering service and closing Zeroconf...\")\n        if info:\n            zeroconf.unregister_service(info)\n        zeroconf.close()\n    print(\"Cleanup complete.\")","lang":"python","description":"This quickstart demonstrates how to register a local HTTP service and simultaneously browse for all HTTP services on the network. It registers 'MyTestService' on port 8080 and then listens for 30 seconds, printing any discovered or removed services. Remember to handle `KeyboardInterrupt` and ensure `Zeroconf` instances are properly closed to release network resources."},"warnings":[{"fix":"Ensure your `pip install` command does not explicitly target `zeroconf==1.0.0`. Stick to `zeroconf` or `zeroconf~=0.x.x`.","message":"The 1.0.0 release was unintentionally published due to an issue with `python-semantic-release` and was subsequently YANKED. It contained no breaking changes, but users should avoid attempting to install this specific version and instead rely on the latest 0.x.x releases.","severity":"breaking","affected_versions":"1.0.0"},{"fix":"Always wrap your `Zeroconf` usage in a `try...finally` block to ensure `zeroconf.close()` is called, as shown in the quickstart example. Consider using `asyncio` for long-running applications or running `Zeroconf` in a dedicated thread.","message":"It is crucial to explicitly call the `close()` method on your `Zeroconf` instance(s) when you are done with them. Failing to do so will leave sockets open and consume resources, potentially leading to 'address already in use' errors or resource leaks.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Pass a list of interface IPs (e.g., `interfaces=['192.168.1.2', '10.0.0.5']`) to the `Zeroconf` constructor: `zeroconf = Zeroconf(interfaces=my_interfaces)`.","message":"On systems with multiple network interfaces, `zeroconf` might not bind to the desired interface by default. If your service isn't discoverable or you're not seeing other services, explicitly specify the network interfaces to use during `Zeroconf` initialization.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}