Sonos Music API - Getting Started Guide

Universal search

Universal search enables Sonos users to find content across multiple music services on a Sonos app. Users can find content throughout different categories, such as artists, tracks, albums, or others. Users must have an account on a music service for it to be shown in the results. Sonos apps display results alphabetically by music service. The screen shot below shows the results of a search on the Sonos App for AndroidTM Smartphones.

Universal search

Sonos provides two different ways of searching for content. Your service must support both methods of searching to provide your listeners with the best Sonos experience.

Listeners using the Sonos app on a Mac or PC can perform a keyword search across categories in your service. Implement this by responding to a getMetadata request for search with a list of categories. See the search SMAPI request and the Support getMetadata search requests for older software versions section below for details.

Listeners using the Sonos app for iOS or Android can perform a category search across multiple services at once. Implement this by sending a list of searchable categories from your presentation map. See the rest of this document for details.

how search works

  1. User searches for an artist, album, track, or other category in the search box on the Sonos app.
  2. The Sonos app sends the search request entered by the user to your service through the SMAPI search() method.
  3. Your service returns the results and the Sonos app aggregates and displays them.

You can offer varying degrees of search:

  • Category search - offer search results using the standard Sonos search categories.
  • Custom Category - offer search results using a category customized to your music service.
  • Multiple Library Search - offer search results within the context of different libraries, such as a global library and a user-specific library.

You can combine these search methods to offer an extensive solution for your service. They are described below in order of complexity.

Category search

In order to offer search across all services, Sonos standardized category names. Search categories are integrated into the presentation map. The <PresentationMap> element uses a "Search" type to specify your search categories and mappings. Use a <Category> element inside a <SearchCategories> element inside a <Match> element to map a known canonical search ID to the SMAPI ID that you've defined for your service, using the id and mappedId attributes, or omit the mappedId type to use a default SMAPI ID.

  • The id attribute is the canonical search ID.
  • The mappedId attribute is the search term that your SMAPI implementation expects.

For example, in one of the mappings below, the "user" category is mapped to the Sonos canonical search ID "people".

<PresentationMap type="Search">
    <Match>
        <SearchCategories>
            <Category mappedId="artist" id="artists"/>
            <Category mappedId="album" id="albums"/>
            <Category mappedId="track" id="tracks"/>
            <Category mappedId="playlist" id="playlists"/>
            <Category mappedId="user" id="people"/>
        </SearchCategories>
    </Match>
</PresentationMap>

See below for the full list of Sonos canonical search IDs.

Category attributes

A Category type has the following attributes:

Name Type Description
id CanonicalSearchId Defines unique identifiers for known categories of searchable items across SMAPI services. One of the following is required:
  • artists
  • albums
  • composers
  • genres
  • hosts
  • podcasts
  • people
  • playlists
  • stations
  • tags
  • tracks
mappedId string The SMAPI identifier for the category used by the music service in the SMAPI search() method. This is optional.

Custom Category search

Use a <CustomCategory> element inside a <SearchCategories> element inside a <Match> element to define a searchable type that is not defined as a Sonos canonical search ID.

<PresentationMap type="Search">
  <Match>
    <SearchCategories>
      ...
      <CustomCategory mappedId="my:custom:smapi_id:concerts" stringId="Concerts"/>
    </SearchCategories>
  </Match>
</PresentationMap>

Add text for the custom search category to the strings.xml file and use the stringId value to identify this value in the strings.xml file. Sonos apps use the string entry for the UI and pass the mappedId value back to your service through the SMAPI search() method when the listener attempts to search for it.

<stringtables xmlns="http://sonos.com/sonosapi">
  <stringtable rev="1" xml:lang="en-US">
    <string stringId="Concerts">Concerts</string>
  </stringtable>
  ...
</stringtables>

Be sure that your custom category doesn't search the same fields as an existing Sonos category. If this is the case, you should use the existing category.

CustomCategory attributes

A CustomCategory type has the following attributes.

Name Type Description
mappedId string The SMAPI identifier for the category passed to the SMAPI search() method. This is required.
stringId string The string entry from strings.xml used for the UI for the custom search category. This is required.

Multiple Library search

Sonos supports multiple searches for the same category in different contexts, for example, if your service offers a global library of songs as well as a user-specific library of songs, a user can search for a song and see the results in the global library as well as their own user library. Sonos apps for mobile devices display the search context within the search results for your service:

And Sonos apps for Windows and Mac OS offer users the ability to choose the context to search:

Use multiple <SearchCategories> elements to support search results grouped by context, and then use a stringId attribute in the <SearchCategories> element to define the context for the search. Use a <Category> element inside a <SearchCategories> element to define search categories.

<PresentationMap type="Search">
    <Match>
        <!-- First grouping, for user content -->
        <SearchCategories stringId="SEARCH_USER_CONTENT">
            <Category id="tracks" mappedId="search:tracks:1"/>
            <Category id="albums" mappedId="search:albums:1"/>
            <Category id="artist" mappedId="search:artist:1"/>
            <Category id="playlists" mappedId="search:playlists:1"/>
            <Category id="tags" mappedId="search:tags:1"/>
            <CustomCategory stringId="SEARCH_CUSTOM" mappedId="search:custom:1"/>
        </SearchCategories>
 
        <!-- Second grouping, for global content -->
        <SearchCategories stringId="SEARCH_GLOBAL_CONTENT">
            <Category id="tracks" mappedId="search:tracks:0"/>
            <Category id="albums" mappedId="search:albums:0"/>
            <Category id="artists" mappedId="search:artists:0"/>
            <CustomCategory stringId="SEARCH_CUSTOM" mappedId="search:custom:0"/>
        </SearchCategories>                  
    </Match>
</PresentationMap>

While mappedId is an optional attribute of the <Category> element, you should use this attribute when using multiple category groups to be sure that you can disambiguate them at the endpoint of your service.

The Sonos app displays the search results in the order you specify in the presentation map. In the example above, the results for SEARCH_USER_CONTENT will be displayed above the results for SEARCH_GLOBAL_CONTENT.

Define the text to use in the user interface in the strings.xml file for these stringId keys.

<stringtables xmlns="http://sonos.com/sonosapi">
  <stringtable rev="1" xml:lang="en-US">
    <string stringId="SEARCH_USER_CONTENT">Local Library</string>
  </stringtable>
  <stringtable rev="1" xml:lang="en-US">
    <string stringId="SEARCH_GLOBAL_CONTENT">Global Library</string>
  </stringtable>
  ...
</stringtables>

Context Search ATTRIBUTES

Implement context search on your existing category or custom category search using the mappedId attribute as defined below.

Name Type Description
mappedId string The SMAPI identifier for the category passed to the SMAPI search() method. You should have a method to determine the search category grouping; in the example above, this is determined by appending a ":0" and ":1".

Presentation Map Configuration Examples

The <SearchCategories> element details the searchable asset types that your service provides, such as tracks, albums, stations, playlists, and so on. This element was added as of build 26.1-73040 and above. Sonos apps using build 38.1 and above can add multiple <SearchCategories> elements to enable context search.

The service in this example supports searchable Artists, Albums, and Tracks using default SMAPI IDs:

<PresentationMap type="Search">
  <Match>
    <SearchCategories>
      <Category id="artists" />
      <Category id="albums" />
      <Category id="tracks" />
    </SearchCategories>
  </Match>
</PresentationMap>

This example shows a service that supports searchable Artists, Albums, and Tracks but the SMAPI IDs for searching on those categories are different than the default:

<PresentationMap type="Search">
  <Match>
    <SearchCategories>
      <Category id="artists" mappedId="my:custom:smapi_id:artist" />
      <Category id="albums" mappedId="my:custom:smapi_id:album" />
      <Category id="tracks" mappedId="my:custom:smapi_id:track" />
      <Category id="podcasts" mappedId="my:custom:smapi_id:shows" />
    </SearchCategories>
  </Match>
</PresentationMap>

This example shows a service that supports searchable Artist, Albums, and Tracks using a mix of default SMAPI IDs and custom SMAPI IDs, along with a CustomCategory that is not found in the Canonical Search Categories:

<PresentationMap type="Search">
  <Match>
    <SearchCategories>
      <Category id="artists" />
      <Category id="albums" mappedId="my:custom:smapi_id:album" />
      <Category id="tracks" mappedId="my:custom:smapi_id:track" />
      <CustomCategory mappedId="my:custom:smapi_id:concerts" stringId="Concerts"/>
    </SearchCategories>
  </Match>
</PresentationMap>

In the example above, the Sonos app will allow searching for Artists, Albums, Tracks, and Concerts. The Sonos app will use the stringId as the default display text. To localize this string, you must add an entry in strings.xml that maps the stringId to appropriate text.

Strings XML Localization

Following the existing Sonos app localization functionality, Sonos apps will use the stringId from the presentation map configuration of a CustomCategory, and look up the string node in the strings.xml configuration with the same stringId using the language setting from the Sonos app to get the text that will be displayed to the listener.

If a matching stringId is not found, the Sonos app will default to the text configured as the stringId in the presentation map as a fallback.

<?xml version="1.0" encoding="utf-8" ?>
<stringtables xmlns="http://sonos.com/sonosapi">
  <stringtable rev="1" xml:lang="en-US">
    <string stringId="Concerts">Concerts</string>
  </stringtable>
  <stringtable rev="1" xml:lang="da-DK">
    <string stringId="Concerts">Koncerter</string>
  </stringtable>
  <stringtable rev="1" xml:lang="de-DE">
    <string stringId="Concerts">Konzerte</string>
  </stringtable>
  <stringtable rev="1" xml:lang="es-ES">
    <string stringId="Concerts">Conciertos</string>
  </stringtable>
  <stringtable rev="1" xml:lang="fr-FR">
    <string stringId="Concerts">Concerts</string>
  </stringtable>
  <stringtable rev="1" xml:lang="it-IT">
    <string stringId="Concerts">Concerti</string>
  </stringtable>
  <stringtable rev="1" xml:lang="ja-JP">
    <string stringId="Concerts">コンサート</string>
  </stringtable>
  <stringtable rev="1" xml:lang="nb-NO">
    <string stringId="Concerts">Konserter</string>
  </stringtable>
  <stringtable rev="1" xml:lang="nl-NL">
    <string stringId="Concerts">Concerten</string>
  </stringtable>
  <stringtable rev="1" xml:lang="pt-BR">
    <string stringId="Concerts">Concertos</string>
  </stringtable>
  <stringtable rev="1" xml:lang="sv-SE">
    <string stringId="Concerts">Konserter</string>
  </stringtable>
  <stringtable rev="1" xml:lang="zh-CN">
    <string stringId="Concerts">音乐会</string>
  </stringtable>
</stringtables>

SMAPI Interaction

With the proper configuration, Sonos apps will use the presentation map to configure universal search. When a listener searches for a given term, the Sonos app will submit a request to your SMAPI search endpoint for each of the SearchCategories you have defined in the presentation map simultaneously. Using the last presentation_map.xml configuration as an example, the Sonos app will emit four SMAPI calls asynchronously:

  • search("artists", "my term", 0, 100)
  • search("my:custom:smapi_id:album", "my term", 0, 100)
  • search("my:custom:smapi_id:track", "my term", 0, 100)
  • search("my:custom:smapi_id:concerts", "my term", 0, 100)

The Sonos app then aggregates the results sent by your service and displays them accordingly. See the search method for sample requests and responses.

Support getmetadata search requests for older software versions

You must implement search for Sonos apps for mobile devices, Windows, and Mac OS. Implement search for mobile devices by sending a list of searchable categories in the <SearchCategories> element in the presentation map as described above. Implement it for Windows and Mac OS by sending these categories in a response to a getMetadata request on the search container.

request

The Sonos app for Windows and Mac OS sends a getMetadata request on the search container for your service:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soapenv:Header>
      <ns:credentials>
        ...
      </ns:credentials>
   </soapenv:Header>
   <soapenv:Body>
      <ns:getMetadata>
         <ns:id>search</ns:id>
         <ns:index>0</ns:index>
         <ns:count>10</ns:count>
      </ns:getMetadata>
   </soapenv:Body>
</soapenv:Envelope>

response

Your service should respond with the search categories:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <s:Body>
      <ns:getMetadataResponse>
         <ns:getMetadataResult>
            <ns:index>0</ns:index>
            <ns:count>2</ns:count>
            <ns:total>2</ns:total>
            <ns:mediaCollection>
               <ns:id>search:songs</ns:id>
               <ns:itemType>search</ns:itemType>
               <ns:title>Songs</ns:title>
               <ns:canPlay>false</ns:canPlay>
               <ns:albumArtURI/>
            </ns:mediaCollection>
            <ns:mediaCollection>
               <ns:id>search:artists</ns:id>
               <ns:itemType>search</ns:itemType>
               <ns:title>Artists</ns:title>
               <ns:canPlay>false</ns:canPlay>
               <ns:albumArtURI/>
            </ns:mediaCollection>
         </ns:getMetadataResult>
      </ns:getMetadataResponse>
   </s:Body>
</s:Envelope>

See search for details.

Sonos app for windows or mac os

In the Sonos app for Windows or Mac OS, the user searches for "Rock" in the "Artists" category:

In the example above, the Sonos app sends the following request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soapenv:Header>
      <ns:credentials>
         <ns:loginToken>
            <ns:token>ABCDEFGHIJK123</ns:token>
            <ns:key>keyvalue</ns:key>
            <ns:householdId>householdId</ns:householdId>
         </ns:loginToken>
      </ns:credentials>
   </soapenv:Header>
   <soapenv:Body>
      <ns:search>
         <ns:id>search:artists</ns:id>
         <ns:term>rock</ns:term>
         <ns:index>0</ns:index>
         <ns:count>10</ns:count>
      </ns:search>
   </soapenv:Body>
</soapenv:Envelope>

The service responds with:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <s:Body>
      <ns:searchResponse>
         <ns:searchResult>
            <ns:index>0</ns:index>
            <ns:count>10</ns:count>
            <ns:total>10</ns:total>
            <ns:mediaCollection>
               <ns:id>artist_abc123</ns:id>
               <ns:itemType>artist</ns:itemType>
               <ns:title>Rock Sound</ns:title>
               <ns:canPlay>false</ns:canPlay>
               <ns:canEnumerate>true</ns:canEnumerate>
               <ns:albumArtURI>https://cdn.example.com/artist_abc123.jpg</ns:albumArtURI>
            </ns:mediaCollection>
            <ns:mediaCollection>
               <ns:id>artist_abc456</ns:id>
               <ns:itemType>artist</ns:itemType>
               <ns:title>Bebble Rock</ns:title>
               <ns:canPlay>false</ns:canPlay>
               <ns:canEnumerate>true</ns:canEnumerate>
               <ns:albumArtURI>https://cdn.example.com/artist_abc456.jpg</ns:albumArtURI>
            </ns:mediaCollection>
            <ns:mediaCollection>
               <ns:id>artist_bcd789</ns:id>
               <ns:itemType>artist</ns:itemType>
               <ns:title>Q107Toronto</ns:title>
               <ns:canPlay>false</ns:canPlay>
               <ns:canEnumerate>true</ns:canEnumerate>
               <ns:albumArtURI>https://cdn.example.com/artist_bcd789.jpg</ns:albumArtURI>
            </ns:mediaCollection>
            ...
         </ns:searchResult>
      </ns:searchResponse>
   </s:Body>
</s:Envelope>

Self-Test & review

Our SMAPI Self-Test can help you during development of the Universal Search feature. First, validate the presentation map against the XSD included in the Self-Test. Then, if applicable, verify the strings.xml file. Finally, verify search functionality.

python ./presentationmap.py --config my_service.cfg

SUITE Summary Report Files: SummaryReport.html and Presentation-map-Validation.txt
SUITE Detailed Debug Log File: Presentation-map-Validation-DEBUG.log
SUITE Start *test suite* 'Presentation map Validation' at Thursday, March 20, 2014 10:10 AM
INFO -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
INFO Start Test Case: 1 Presentationmap test_presentation_map
PASS 1 Presentationmap test_presentation_map
SUITE Summary: Passed. Passed: 1, Failed: 0.

PYTHON ./stringtable.PY --CONFIG MY_SERVICE.CFG

SUITE Summary Report Files: SummaryReport.html and Stringtable-Validation.txt
SUITE Detailed Debug Log File: Stringtable-Validation-DEBUG.log
SUITE Start *test suite* 'Stringtable Validation' at Thursday, March 20, 2014 10:13 AM
INFO -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
INFO Test Case: 1 Stringtable test_combinatorial_all_languages en-US)
PASS 1 Stringtable test_combinatorial_all_languages
...
INFO -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
INFO Start Test Case: 16 Stringtable test_unsupported_languages
PASS 16 Stringtable test_unsupported_languages
SUITE Summary: Passed. Passed: 15, Failed: 0.

PYTHON ./search.PY --CONFIG MY_SERVICE.CFG

SUITE Summary Report Files: SummaryReport.html and SMAPI-Search-Validation.txt
SUITE Detailed Debug Log File: SMAPI-Search-Validation-DEBUG.log
SUITE Start *test suite* 'SMAPI Search Validation' at Thursday, March 20, 2014 10:16 AM
INFO -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
INFO Test Case: 1 Search test_combinatorial_item_types itemType)
PASS 1 Search test_combinatorial_item_types
...
INFO -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
INFO Start Test Case: 76 Search test_train_ux_search_configuration
PASS 76 Search test_train_ux_search_configuration
SUITE Summary: Passed. Passed: 33, Failed: 0.