diff --git a/scribus/plugins/scriptplugin/cmdtext.cpp b/scribus/plugins/scriptplugin/cmdtext.cpp
index d27e31bd99..6bc8f5bf5f 100644
--- a/scribus/plugins/scriptplugin/cmdtext.cpp
+++ b/scribus/plugins/scriptplugin/cmdtext.cpp
@@ -1354,6 +1354,74 @@ PyObject *scribus_ispdfbookmark(PyObject* /* self */, PyObject* args)
 	return PyBool_FromLong(0);
 }
 
+PyObject *scribus_getcharcoordinates(PyObject* /* self */, PyObject* args)
+{
+	int pos;
+	char *Name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "i|es", &pos, "utf-8", &Name))
+		return nullptr;
+	if (!checkHaveDocument())
+		return nullptr;
+	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
+	if (item == nullptr)
+		return nullptr;
+	if (!(item->isTextFrame()) && !(item->isPathText()))
+	{
+		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get character positions from a non-text frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	if ((pos < 0) || (pos >= static_cast<int>(item->itemText.length())))
+	{
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index out of bounds.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	// When chaining the frame the char is in doesn't necessarily match
+	// the selected frame.
+	PageItem* actual = item->frameOfChar(pos);
+	if (actual == nullptr) {
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index not visible in a frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	QLineF box = actual->textLayout.positionToPoint(pos);
+	return Py_BuildValue("(idddd)",
+			     // Scripter API page starts at 1, not 0.
+			     actual->OwnPage + 1,
+			     docUnitXToPageX(actual->xPos() + box.x1()),
+			     docUnitYToPageY(actual->yPos() + box.y1()),
+			     PointToValue(box.x2() - box.x1()),
+			     PointToValue(box.y2() - box.y1()));
+}
+
+PyObject *scribus_getmark(PyObject* /* self */, PyObject* args)
+{
+	int pos;
+	char *Name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "i|es", &pos, "utf-8", &Name))
+		return nullptr;
+	if (!checkHaveDocument())
+		return nullptr;
+	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
+	if (item == nullptr)
+		return nullptr;
+	if (!(item->isTextFrame()) && !(item->isPathText()))
+	{
+		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get mark info from a non-text frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	if ((pos < 0) || (pos >= static_cast<int>(item->itemText.length())))
+	{
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index out of bounds.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	Mark* mark = item->itemText.mark(pos);
+	if (mark) {
+	  return Py_BuildValue("(is)", mark->getType(),
+			       mark->getData().strtxt.toUtf8().data());
+	} else {
+	  return Py_BuildValue("(is)", MARKNoType, "");
+	}
+}
+
 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
 with header files structure untouched (docstrings are kept near declarations)
 PV */
@@ -1370,6 +1438,7 @@ void cmdtextdocwarnings()
 	  << scribus_getfontsize__doc__
 	  << scribus_getframetext__doc__
 	  << scribus_getlinespace__doc__
+	  << scribus_getmark__doc__
 	  << scribus_gettext__doc__ // Deprecated
 	  << scribus_gettextcolor__doc__
 	  << scribus_gettextdistances__doc__
@@ -1386,6 +1455,7 @@ void cmdtextdocwarnings()
 	  << scribus_layouttextchain__doc__
 	  << scribus_linktextframes__doc__
 	  << scribus_outlinetext__doc__
+	  << scribus_getcharcoordinates__doc__
 	  << scribus_selecttext__doc__
 	  << scribus_setalign__doc__
 	  << scribus_setcolumngap__doc__
diff --git a/scribus/plugins/scriptplugin/cmdtext.h b/scribus/plugins/scriptplugin/cmdtext.h
index bad04bbad8..3a0f5cbe4c 100644
--- a/scribus/plugins/scriptplugin/cmdtext.h
+++ b/scribus/plugins/scriptplugin/cmdtext.h
@@ -581,4 +581,30 @@ May raise WrongFrameTypeError if the target frame is not a text frame\n\
 /*! Is PDF bookmark? */
 PyObject *scribus_ispdfbookmark(PyObject * /*self*/, PyObject* args);
 
+/*! docstring */
+PyDoc_STRVAR(scribus_getcharcoordinates__doc__,
+QT_TR_NOOP("getCharCoordinates(pos, [\"name\"]) -> (page,x,y,width,height)\n\
+\n\
+Returns a (page, x, y, width, height) tuple based on the character at\n\
+position \"pos\" in the text frame \"name\". If the text frame is chained\n\
+from another text frame, \"pos\" is based on the overall story text. If\n\
+ \"name\" is not given the currently selected item is used.\n\
+\n\
+Will only work properly if the text has been layed out; you may need to call\n\
+layoutText() or layoutTextChain() first for correct results.\n\
+"));
+/*! Point for glyth at position */
+PyObject *scribus_getcharcoordinates(PyObject * /*self*/, PyObject* args);
+
+/*! docstring */
+PyDoc_STRVAR(scribus_getmark__doc__,
+QT_TR_NOOP("getMark(pos, [\"name\"]) -> (type,text)\n\
+\n\
+Returns a (type, text) tuple for the mark at position pos in object \"name\".\n\
+If \"name\" is not given the currently selected item is used. If there is no\n\
+mark at that position, type is -1.\n\
+"));
+/*! Returns info about mark */
+PyObject *scribus_getmark(PyObject * /*self*/, PyObject* args);
+
 #endif
diff --git a/scribus/plugins/scriptplugin/scriptplugin.cpp b/scribus/plugins/scriptplugin/scriptplugin.cpp
index a9b5497d60..644e8313dd 100644
--- a/scribus/plugins/scriptplugin/scriptplugin.cpp
+++ b/scribus/plugins/scriptplugin/scriptplugin.cpp
@@ -414,6 +414,8 @@ PyMethodDef scribus_methods[] = {
 	{const_cast<char*>("getUnit"), (PyCFunction)scribus_getunit, METH_NOARGS, tr(scribus_getunit__doc__)},
 	{const_cast<char*>("getVGuides"), (PyCFunction)scribus_getVguides, METH_NOARGS, tr(scribus_getVguides__doc__)},
 	{const_cast<char*>("getXFontNames"), (PyCFunction)scribus_xfontnames, METH_NOARGS, tr(scribus_xfontnames__doc__)},
+	{const_cast<char*>("getCharCoordinates"), scribus_getcharcoordinates, METH_VARARGS, tr(scribus_getcharcoordinates__doc__)},
+	{const_cast<char*>("getMark"), scribus_getmark, METH_VARARGS, tr(scribus_getmark__doc__)},
 	{const_cast<char*>("gotoPage"), scribus_gotopage, METH_VARARGS, tr(scribus_gotopage__doc__)},
 	{const_cast<char*>("groupObjects"), (PyCFunction)scribus_groupobj, METH_VARARGS, tr(scribus_groupobj__doc__)},
 	{const_cast<char*>("haveDoc"), (PyCFunction)scribus_havedoc, METH_NOARGS, tr(scribus_havedoc__doc__)},
