diff --git a/src/modules/pid/i18n/de.ts b/src/modules/pid/i18n/de.ts
index 9e6d76a460b2fb3227d9a5e12a5b1ae2856eadbb..0596309599628156b9cd4198eb22c434d91d07b3 100644
--- a/src/modules/pid/i18n/de.ts
+++ b/src/modules/pid/i18n/de.ts
@@ -19,6 +19,8 @@ export default {
         "In den meisten Fällen sind die referenzierten Daten nicht öffentlich zugänglich. Sie können sich daher an den Besitzer der Daten wenden und um Zugang bitten. Der Besitzer dieser Ressource wird dann von Coscine kontaktiert. Die Informationen, die Sie im Formular angeben, werden so an den Besitzer weitergeleitet.",
 
       toClipboard: "PID wurde in die Zwischenablage kopiert",
+      toLocation: "Speicherort wurde in die Zwischenablage kopiert",
+      openUrl: "Navigieren Sie zur Objekt-URL in einem neuen Tab",
 
       form: {
         labelSymbol: ":",
@@ -29,6 +31,9 @@ export default {
         persistentIdPopover:
           "Für weitere Informationen zum @:(page.pid.form.persistentId) siehe",
         persistentIdPopoverUrl: "https://docs.coscine.de/de/resources/pid/",
+        objectLocation: "Speicherort",
+        objectLocationLabel:
+          "@:(page.pid.form.objectLocation)@:(page.pid.form.labelSymbol)",
 
         yourName: "Ihr Name",
         yourNameLabel:
diff --git a/src/modules/pid/i18n/en.ts b/src/modules/pid/i18n/en.ts
index 538ba77430fbe54b32a6a5a25239b7d71bfc9edc..fbcdb291f0eb7c14350d55c8558498433c160206 100644
--- a/src/modules/pid/i18n/en.ts
+++ b/src/modules/pid/i18n/en.ts
@@ -19,6 +19,8 @@ export default {
         "In most cases the referenced data is not publicly available. You can contact the owner of the data to ask for access. The owner of this resource will be contacted by Coscine. The information you provide in the form will be relayed to the owner.",
 
       toClipboard: "PID has been copied to clipboard",
+      toLocation: "Object location has been copied to clipboard",
+      openUrl: "Navigate to the object location in a new tab",
 
       form: {
         labelSymbol: ":",
@@ -29,6 +31,9 @@ export default {
         persistentIdPopover:
           "For more information on @:(page.pid.form.persistentId) see",
         persistentIdPopoverUrl: "https://docs.coscine.de/en/resources/pid/",
+        objectLocation: "Object Location",
+        objectLocationLabel:
+          "@:(page.pid.form.objectLocation)@:(page.pid.form.labelSymbol)",
 
         yourName: "Your Name",
         yourNameLabel:
diff --git a/src/modules/pid/pages/Pid.vue b/src/modules/pid/pages/Pid.vue
index c25ee7b242b7d16d333186f911875eeb87fac862..afe5ed19d7a2664422927e08fe5c0b9a836330b9 100644
--- a/src/modules/pid/pages/Pid.vue
+++ b/src/modules/pid/pages/Pid.vue
@@ -50,6 +50,56 @@
         </b-tooltip>
       </b-button-group>
     </CoscineFormGroup>
+
+    <!-- Object Location -->
+    <CoscineFormGroup
+      v-if="digitalObjectLocation"
+      label-for="ObjectLocation"
+      :label="$t('page.pid.form.objectLocationLabel')"
+    >
+      <b-button-group class="w-100">
+        <!-- Text Field -->
+        <b-form-input
+          id="ObjectLocation"
+          v-model="digitalObjectLocation"
+          :readonly="true"
+        />
+
+        <!-- Open URL Button -->
+        <b-button
+          v-if="isPidUiUrlFound"
+          id="openUrlButton"
+          @click="openObjectLocation()"
+        >
+          <b-icon icon="link-45deg" />
+        </b-button>
+        <!-- Copy Button -->
+        <b-button v-else id="copyObjectLocation" @click="copyUrl">
+          <b-icon icon="clipboard" />
+        </b-button>
+
+        <!-- Open URL Tooltip -->
+        <b-tooltip
+          v-if="isPidUiUrlFound"
+          id="openUrlTooltip"
+          target="openUrlButton"
+          placement="top"
+          triggers="hover focus"
+        >
+          {{ $t("page.pid.openUrl") }}
+        </b-tooltip>
+        <!-- Copied Tooltip -->
+        <b-tooltip
+          v-else
+          id="copyObjectLocationTooltip"
+          target="copyObjectLocation"
+          placement="top"
+          triggers="blur"
+        >
+          {{ $t("page.pid.toLocation") }}
+        </b-tooltip>
+      </b-button-group>
+    </CoscineFormGroup>
     <div class="h-divider" />
 
     <!-- Contact PID Owner -->
@@ -149,16 +199,24 @@ import usePidStore from "../store";
 import useNotificationStore from "@/store/notification";
 import { useVuelidate, type ValidationArgs } from "@vuelidate/core";
 import { email, maxLength, required } from "@vuelidate/validators";
-import type { PidRequestDto } from "@coscine/api-client/dist/types/Coscine.Api";
+import {
+  type HandleDto,
+  type PidRequestDto,
+} from "@coscine/api-client/dist/types/Coscine.Api";
+import { handleUrl, pidHandles } from "../utils/constants";
+import useProjectStore from "@/modules/project/store";
+import useResourceStore from "@/modules/resource/store";
 
 export default defineComponent({
   setup() {
     const pidStore = usePidStore();
+    const projectStore = useProjectStore();
+    const resourceStore = useResourceStore();
     const notificationStore = useNotificationStore();
 
     const v$ = useVuelidate();
 
-    return { pidStore, notificationStore, v$ };
+    return { pidStore, projectStore, resourceStore, notificationStore, v$ };
   },
 
   data() {
@@ -169,8 +227,11 @@ export default defineComponent({
         message: "",
         sendConfirmationEmail: true,
       } satisfies PidRequestDto,
+      handle: undefined as HandleDto | undefined,
+      digitalObjectLocation: undefined as string | undefined,
       isLoading: false,
       isPidValid: null as boolean | null,
+      isPidUiUrlFound: false,
     };
   },
 
@@ -178,9 +239,27 @@ export default defineComponent({
     pid(): string | null {
       const pid = this.$route.query["pid"];
       if (pid) {
-        return pid.toString().replace("http://hdl.handle.net/", "");
+        return pid.toString().replace(handleUrl, "");
       } else return null;
     },
+    /**
+     * A computed property that decodes the base64-encoded path from the URL hash.
+     * If the hash is not specified, an empty string will be returned.
+     * @returns {string} The decoded path from the URL hash.
+     */
+    path(): string {
+      const hash = this.$route.hash;
+      // Check for hash
+      if (hash) {
+        // Hash always starts with '#', trim it
+        const parsedHash = new URLSearchParams(this.$route.hash.substring(1));
+        // Url decode
+        const path = decodeURI(parsedHash.get("path") ?? "");
+        //Base64 decode
+        return Buffer.from(path, "base64").toString();
+      }
+      return "";
+    },
   },
 
   validations() {
@@ -198,6 +277,17 @@ export default defineComponent({
     async pid() {
       await this.validatePid();
     },
+    handle: {
+      async handler() {
+        // Try to build the UI URL from the PID, if it fails, use the digital object location from the handle
+        this.digitalObjectLocation =
+          (await this.buildUiUrlFromPid()) ??
+          this.handle?.values?.find(
+            (h) => h.type === pidHandles.digitalObjectLocation,
+          )?.parsed_data;
+      },
+      deep: true,
+    },
   },
 
   async created() {
@@ -207,10 +297,73 @@ export default defineComponent({
   methods: {
     copyPid() {
       if (this.pid) {
-        navigator.clipboard.writeText("http://hdl.handle.net/" + this.pid);
+        navigator.clipboard.writeText(handleUrl + this.pid);
         this.$root.$emit("bv::show::tooltip", "copyPidTooltip");
       }
     },
+    copyUrl() {
+      if (this.digitalObjectLocation) {
+        navigator.clipboard.writeText(this.digitalObjectLocation);
+        this.$root.$emit("bv::show::tooltip", "copyObjectLocationTooltip");
+      }
+    },
+    openObjectLocation() {
+      if (this.digitalObjectLocation) {
+        window.open(this.digitalObjectLocation, "_blank");
+      }
+    },
+    /**
+     * Asynchronously builds a UI URL based on the PID of the handle object.
+     *
+     * @method buildUiUrlFromPid
+     * @async
+     * @returns {Promise<string | undefined>} A promise that resolves to a string representing the UI URL, or undefined if the PID suffix is not found.
+     *
+     * The method works as follows:
+     * 1. If the PID type is "project", it fetches the project by its ID and constructs a route to the project page.
+     * 2. If the PID type is "resource", it fetches the resource by its ID and constructs a route to the resource page.
+     * 3. If a route is found, it sets the `isPidUiUrlFound` flag to true.
+     * 4. Finally, it returns the constructed URL, or undefined if no PID suffix was found.
+     */
+    async buildUiUrlFromPid(): Promise<string | undefined> {
+      const id = this.handle?.pid?.suffix;
+      if (!id) return;
+      let route;
+      let projectSlug;
+      // Process type "project"
+      if (this.handle?.pid?.type === "project") {
+        const project = await this.projectStore.getProjectById(
+          id,
+          /*silent*/ true,
+        );
+        if (project && project.slug) {
+          projectSlug = project.slug;
+          route = this.$router.resolve({
+            name: "project-page",
+            params: { slug: projectSlug },
+          });
+        }
+      }
+      // Process type "resource"
+      if (this.handle?.pid?.type === "resource") {
+        const resource = await this.resourceStore.getResourceById(
+          id,
+          /*silent*/ true,
+        );
+        if (resource && resource.projects && resource.projects.length > 0) {
+          projectSlug = resource.projects[0].id;
+          route = this.$router.resolve({
+            name: "resource-page",
+            params: { slug: projectSlug!, guid: id, dirTrail: this.path },
+          });
+        }
+      }
+      if (route) {
+        // We found a route
+        this.isPidUiUrlFound = true;
+        return `${window.location.origin}${route?.href}`;
+      }
+    },
     async validatePid() {
       this.isLoading = true;
       if (this.pid) {
@@ -218,6 +371,7 @@ export default defineComponent({
         const id = this.pid.split("/").at(1);
         if (prefix && id) {
           this.isPidValid = await this.pidStore.validatePid(prefix, id);
+          this.handle = await this.pidStore.getHandle(prefix, id);
         }
       }
       this.isLoading = false;
diff --git a/src/modules/pid/store.ts b/src/modules/pid/store.ts
index f96b452809578e57749404eacf332b189459ecf3..87cc041abbceeb697e7dd17f5c4c51a63d5004a8 100644
--- a/src/modules/pid/store.ts
+++ b/src/modules/pid/store.ts
@@ -3,9 +3,13 @@ import type { PidState } from "./types";
 
 import useNotificationStore from "@/store/notification";
 import { PidApi } from "@coscine/api-client";
+import { HandleApi } from "@coscine/api-client";
 import { AxiosError } from "axios";
 import { StatusCodes } from "http-status-codes";
-import type { PidRequestDto } from "@coscine/api-client/dist/types/Coscine.Api";
+import type {
+  HandleDto,
+  PidRequestDto,
+} from "@coscine/api-client/dist/types/Coscine.Api";
 
 /*  
   Store variable name is "this.<id>Store"
@@ -65,7 +69,25 @@ export const usePidStore = defineStore({
         return null;
       }
     },
-
+    /**
+     * Retrieves the PID handles using the provided PID prefix and ID.
+     * @param {string} prefix - The PID prefix value.
+     * @param {string} suffix - The ID value.
+     * @returns {Promise<HandleDto | undefined>} A promise that resolves to the handle data if successful, or undefined if there was an error.
+     */
+    async getHandle(
+      prefix: string,
+      suffix: string,
+    ): Promise<HandleDto | undefined> {
+      const notificationStore = useNotificationStore();
+      try {
+        const apiResponse = await HandleApi.getHandle({ prefix, suffix });
+        return apiResponse.data.data;
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+      }
+    },
     /**
      * Contacts the PID owner using the provided PID prefix, ID, and PID enquiry data.
      * @param {string} prefix - The PID prefix value.
diff --git a/src/modules/pid/types.ts b/src/modules/pid/types.ts
index 61d187bb4a6b6efaafa7d91a6862ea1a86b57a08..e9565ed6e32a13bf9aaa482a42878a5d5e62cd1d 100644
--- a/src/modules/pid/types.ts
+++ b/src/modules/pid/types.ts
@@ -6,3 +6,40 @@ export interface PidState {
     --------------------------------------------------------------------------------------
   */
 }
+
+/**
+ * Provides a collection of constant identifiers relevant to the Coscine PID Record.
+ * These identifiers represent entries in the Data Type Registry (DTR) and are used to identify various
+ * types of information within the PID system.
+ */
+export interface PidHandles {
+  /** The general identifier for the Kernel Information Profile type. */
+  kernelInformationProfile: string;
+
+  /** The identifier for the Coscine-specific Kernel Information Profile type. */
+  coscineKernelInformationProfile: string;
+
+  /** The identifier representing the date the PID record was created. */
+  dateCreated: string;
+
+  /** The identifier for identifying the digital object's location. */
+  digitalObjectLocation: string;
+
+  /** The identifier for the digital object type. */
+  digitalObjectType: string;
+
+  /** The identifier for the digital object value corresponding to a resource. */
+  digitalObjectTypeResource: string;
+
+  /** The identifier for the digital object value corresponding to a project. */
+  digitalObjectTypeProject: string;
+
+  /** The identifier representing the type of license associated with the digital object. */
+  license: string;
+
+  /** The identifier for the contact type, representing contact information within the PID record. */
+  contact: string;
+
+  /** The identifier for the topic type, used to categorize or tag the digital object with specific topics. */
+  topic: string;
+}
diff --git a/src/modules/pid/utils/constants.ts b/src/modules/pid/utils/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f455a98b3da3223bea27ac72d097213d040a6323
--- /dev/null
+++ b/src/modules/pid/utils/constants.ts
@@ -0,0 +1,16 @@
+import { PidHandles } from "../types";
+
+export const pidHandles: PidHandles = {
+  kernelInformationProfile: "21.T11148/076759916209e5d62bd5",
+  coscineKernelInformationProfile: "21.T11148/8882327b7c25331e3cdd",
+  dateCreated: "21.T11148/aafd5fb4c7222e2d950a",
+  digitalObjectLocation: "21.T11148/b8457812905b83046284",
+  digitalObjectType: "21.T11148/1c699a5d1b4ad3ba4956",
+  digitalObjectTypeResource: "21.T11148/12aad485b74d04f584c1",
+  digitalObjectTypeProject: "21.T11148/0f13b0a83bd926fe269f",
+  license: "21.T11148/2f314c8fe5fb6a0063a8",
+  contact: "21.T11148/1a73af9e7ae00182733b",
+  topic: "21.T11148/b415e16fbe4ca40f2270",
+};
+
+export const handleUrl = "http://hdl.handle.net/";
diff --git a/src/modules/project/store.ts b/src/modules/project/store.ts
index 0c92c0979cfb00baa9bc597d087ad15c5e2b34c3..6ec5d0eedc3b678495a17e88271f670fb5180402 100644
--- a/src/modules/project/store.ts
+++ b/src/modules/project/store.ts
@@ -257,6 +257,23 @@ export const useProjectStore = defineStore({
       }
     },
 
+    async getProjectById(
+      projectId: string,
+      silent: boolean = false,
+    ): Promise<ProjectDto | null> {
+      const notificationStore = useNotificationStore();
+      try {
+        const apiResponse = await ProjectApi.getProject({ projectId });
+        return apiResponse.data.data as ProjectDto;
+      } catch (error) {
+        if (!silent) {
+          // Handle other Status Codes
+          notificationStore.postApiErrorNotification(error as AxiosError);
+        }
+        return null;
+      }
+    },
+
     async retrieveProjectBySlug(slug: string) {
       const notificationStore = useNotificationStore();
       try {
@@ -649,7 +666,8 @@ export const useProjectStore = defineStore({
         if (!this.visitedProjects[routeParams.slug]) {
           await this.retrieveProjectBySlug(routeParams.slug);
         }
-        this.currentSlug = routeParams.slug;
+        // Handle slug and id
+        this.currentSlug = this.findSlug(routeParams.slug);
       }
     },
 
@@ -920,6 +938,21 @@ export const useProjectStore = defineStore({
         notificationStore.postApiErrorNotification(error as AxiosError);
       }
     },
+
+    findSlug(projectIdOrSlug: string): string | null {
+      // Check if the projectIdOrSlug is a slug
+      if (this.visitedProjects[projectIdOrSlug]) {
+        return projectIdOrSlug;
+      } else {
+        // Check if the projectIdOrSlug is a projectId
+        for (const slug in this.visitedProjects) {
+          if (this.visitedProjects[slug].id === projectIdOrSlug) {
+            return slug;
+          }
+        }
+      }
+      return null;
+    },
   },
 });
 
diff --git a/src/modules/resource/store.ts b/src/modules/resource/store.ts
index 81f17c43efa56af75b3c58d37a6d3f4fc3ae0684..434d7db58433cca3cebb14ddf84076f742896566 100644
--- a/src/modules/resource/store.ts
+++ b/src/modules/resource/store.ts
@@ -17,6 +17,7 @@ import {
   ProjectResourceApi,
   ProjectResourceQuotaApi,
   ProjectResourceTypeApi,
+  ResourceApi,
   ResourceTypeApi,
   TreeApi,
   VocabularyApi,
@@ -179,6 +180,25 @@ export const useResourceStore = defineStore({
       }
     },
 
+    async getResourceById(
+      resourceId: string,
+      silent: boolean = false,
+    ): Promise<ResourceDto | null> {
+      const notificationStore = useNotificationStore();
+      try {
+        const apiResponse = await ResourceApi.getResource({
+          resourceId,
+        });
+        return apiResponse.data.data as ResourceDto;
+      } catch (error) {
+        if (!silent) {
+          // Handle other Status Codes
+          notificationStore.postApiErrorNotification(error as AxiosError);
+        }
+        return null;
+      }
+    },
+
     async retrieveApplicationProfile(resource: VisitedResourceObject) {
       const notificationStore = useNotificationStore();
       try {