diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Backend.php b/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Backend.php
index 818b785f880803c13d5723778f129d2364bc886e..42f0464bd3841d7f57efe506c0689eb81cb1edc5 100644
--- a/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Backend.php
+++ b/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Backend.php
@@ -28,6 +28,8 @@
  */
 namespace VuFindSearch\Backend\Primo;
 
+use VuFindSearch\Feature\RetrieveBatchInterface;
+
 use VuFindSearch\Query\AbstractQuery;
 
 use VuFindSearch\ParamBag;
@@ -47,7 +49,7 @@ use VuFindSearch\Backend\Exception\BackendException;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     http://vufind.org
  */
-class Backend extends AbstractBackend
+class Backend extends AbstractBackend implements RetrieveBatchInterface
 {
     /**
      * Connector.
@@ -146,6 +148,49 @@ class Backend extends AbstractBackend
         return $collection;
     }
 
+    /**
+     * Retrieve a batch of documents.
+     *
+     * @param array    $ids    Array of document identifiers
+     * @param ParamBag $params Search backend parameters
+     *
+     * @return RecordCollectionInterface
+     */
+    public function retrieveBatch($ids, ParamBag $params = null)
+    {
+        // Load 100 records at a time; this is a good number to avoid memory
+        // problems while still covering a lot of ground.
+        $pageSize = 100;
+
+        // Retrieve records a page at a time:
+        $results = false;
+        while (count($ids) > 0) {
+            $currentPage = array_splice($ids, 0, $pageSize, []);
+
+            try {
+                $response = $this->connector->getRecords(
+                    $currentPage, $this->connector->getInstitutionCode()
+                );
+            } catch (\Exception $e) {
+                throw new BackendException(
+                    $e->getMessage(),
+                    $e->getCode(),
+                    $e
+                );
+            }
+            $next = $this->createRecordCollection($response);
+            if (!$results) {
+                $results = $next;
+            } else {
+                foreach ($next->getRecords() as $record) {
+                    $results->add($record);
+                }
+            }
+        }
+        $this->injectSourceIdentifier($results);
+        return $results;
+    }
+
     /**
      * Set the query builder.
      *
diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Connector.php b/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Connector.php
index 67db8328a5b7f5e493db3ee1f524365cae3ffd29..71a51d7a089b14e9133baa0ee720c0f63803c166 100644
--- a/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Connector.php
+++ b/module/VuFindSearch/src/VuFindSearch/Backend/Primo/Connector.php
@@ -604,7 +604,8 @@ class Connector implements \Zend\Log\LoggerAwareInterface
         // Query String Parameters
         if (isset($recordId)) {
             $qs   = [];
-            $qs[] = "query=rid,exact,\"$recordId\"";
+            $qs[] = 'query=rid,exact,"' . urlencode(addcslashes($recordId, '"'))
+                . '"';
             $qs[] = "institution=$inst_code";
             $qs[] = "onCampus=true";
             $qs[] = "indx=1";
@@ -620,6 +621,42 @@ class Connector implements \Zend\Log\LoggerAwareInterface
         return $result;
     }
 
+    /**
+     * Retrieves multiple documents specified by the ID.
+     *
+     * @param array  $recordIds The documents to retrieve from the Primo API
+     * @param string $inst_code Institution code (optional)
+     *
+     * @throws \Exception
+     * @return string    The requested resource
+     */
+    public function getRecords($recordIds, $inst_code = null)
+    {
+        // Callback function for formatting IDs:
+        $formatIds = function ($i) {
+            return '"' . addcslashes($i, '"') . '"';
+        };
+
+        // Query String Parameters
+        if ($recordIds) {
+            $qs   = [];
+            $recordIds = array_map($formatIds, $recordIds);
+            $qs[] = 'query=rid,contains,' . urlencode(implode(' OR ', $recordIds));
+            $qs[] = "institution=$inst_code";
+            $qs[] = "onCampus=true";
+            $qs[] = "indx=1";
+            $qs[] = "bulkSize=" . count($recordIds);
+            $qs[] = "loc=adaptor,primo_central_multiple_fe";
+
+            // Send Request
+            $result = $this->call(implode('&', $qs));
+        } else {
+            throw new \Exception('Primo API does not accept a null query');
+        }
+
+        return $result;
+    }
+
     /**
      * Get the institution code based on user IP. If user is coming from
      * off campus return